NET 4.+ & .NET CORE 高性能 輕量級 ORM框架,眾多.NET框架中最容易使用的數據庫訪問技術
MongoDB與MySql的安裝省略...雖然遇到了一些意外的情況,也花了一些時間,但是網上大都能找到解決方法,就不贅述了。
測試過程中使用的所有第三方庫文件都可以通過Nuget獲取:MySql.Data.dll,Newtonsoft.Json.dll,SqlSugar.dll,MongoDB.Driver.dll,MongoDB.Bson.dll
本文記錄,對10000條數據的插入與讀取速度,來簡單對比三種訪問數據庫的方式哪一種用起來更方便更高效,當然,這可能是片面的,但是結論不是我的目的,我的目的是為了學習了解NoSql數據庫。
考慮一下以下實體對象:Book與Tags一對多關系,要新建兩張表,字段與實體對象中的屬性一一對應
public class BaseEntity { [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] public string Guid { get; set; } [SugarColumn(IsIgnore = true)] public ObjectId id { get; set; } }
public class Book : BaseEntity { /// <summary> /// 標題 /// </summary> public string Title { get; set; } /// <summary> /// 描述 /// </summary> public string Description { get; set; } /// <summary> /// 作者 /// </summary> public string Author { get; set; } /// <summary> /// 價格 /// </summary> public decimal Price { get; set; } /// <summary> /// 標簽 /// </summary> [SugarColumn(IsIgnore = true)] public List<Tags> Tags { get; set; } }
public class Tags : BaseEntity { /// <summary> /// 標簽 /// </summary> public string Tag { get; set; } /// <summary> /// 對應的書的Id /// </summary> public string BookId { get; set; } }
建了兩張表,就很頭疼了,插入數據的時候,要分別插入,這樣的效率是比較低的。這里直接考慮用SqlSugar插入10000條數據
private void btn_insert_mysql_Click(object sender, EventArgs e) { BookRepository db = new BookRepository(); System.Threading.Thread thread = new System.Threading.Thread(() => { Stopwatch stopWatch = new Stopwatch(); stopWatch.Restart(); for (int i = 0; i < 10000; i++) { Book book = CreateData(i); db.Insert(book); } stopWatch.Stop(); WriteLog(string.Format("SqlSugar插入Mysql 10000 條數據耗時:{0}ms", stopWatch.ElapsedMilliseconds)); }); thread.Start(); }
public void Insert(Book book) { db.Insertable<Book>(book).ExecuteCommand(); db.Insertable<Tags>(book.Tags).ExecuteCommand(); }
再往MongoDB中插入10000條數據,MongoDB插入數據就很方便的了,啥都不用管,因為它的數據本來是以文檔的方式存儲的,一種類似於JSON對象的數據結構,叫BSON
private void btn_insert_mongodb_Click(object sender, EventArgs e) { MongoDbHelper<Book> db = new MongoDbHelper<Book>(); System.Threading.Thread thread = new System.Threading.Thread(() => { Stopwatch stopWatch = new Stopwatch(); stopWatch.Restart(); for (int i = 0; i < 10000; i++) { Book book = CreateData(i); db.Insert(book); } stopWatch.Stop(); WriteLog(string.Format("插入MongoDB 10000 條數據耗時:{0}ms", stopWatch.ElapsedMilliseconds)); }); thread.Start(); }
public T Insert(T entity) { collection.InsertOne(entity); return entity; }
插入數據的耗時結果對比:
2018-09-24 13:43:05 插入MongoDB 10000 條數據耗時:3111ms
2018-09-24 13:43:14 SqlSugar插入Mysql 10000 條數據耗時:12924ms

數據准備好了之后,便開始測試查詢。
SqlSugar查詢所有數據:
使用sqlsugar查詢數據有兩種方式,一種分兩次查詢,這種方式最終得到的List中一共10000條數據,
另一種,連表查詢,但是會有30000條數據,且要么返回匿名對象,返回值使用dynamic接收,或者新建一個View Model,總之,需要做一些其他的工作。
public List<Book> GetAll() { List<Book> lstBook = db.Queryable<Book>().ToList(); foreach (var book in lstBook) { book.Tags = db.Queryable<Tags>().Where(x => x.BookId == book.Guid).ToList(); } return lstBook; //var lstBook = db.Queryable<Book, Tags>((bk, tg) => new object[] { JoinType.Left, bk.Guid == tg.BooksId }).Select((bk, tg) => new VBook // { // Guid = bk.Guid, // Author = bk.Author, // Title = bk.Title, // Description = bk.Description, // Price = bk.Price, // Tag = tg.Tag // }).ToList(); //return lstBook; }
Ado.Net查詢:這是最原始的方式了,優勢還是很明顯的,寫原生的sql語句,效率算是比較高了,省去了ORM解析lambda表達式,反射屬性賦值等,SqlSugar是國內的開源項目,有時間的話,可以下載源代碼看看。當
然Ado.Net操作數據庫不方便的地方就是DataTable轉實體對象了,字段多的時候,寫的頭都暈了,沒有技術含量卻要拼命的寫啊寫啊寫....
下面的代碼片段,查詢出來有30000條數據,否則,只能查詢兩次,與上面使用的SqlSugar一樣
public List<Book> GetAllByAdo() { List<Book> lstBook = new List<Book>(); string conn = "Data Source=127.0.0.1;port=3306;Initial Catalog=test;user id=test;password=123456;Charset=utf8;SslMode = none;"; string sql = "select * from book a,tags b where a.Guid=b.BookId"; DataTable dt = MySql.Data.MySqlClient.MySqlHelper.ExecuteDataset(conn, sql).Tables[0]; foreach (DataRow dr in dt.Rows) { Book book = new Book { Guid = dr["Guid"].ToString(), Author = dr["Author"].ToString(), Title = dr["Title"].ToString(), Description = dr["Description"].ToString(), Price = decimal.Parse(dr["Price"].ToString()), Tags = new List<Tags>() { new Tags { Guid = dr["Guid1"].ToString(), BookId = dr["BooksId"].ToString(), Tag = dr["Tag"].ToString() } } }; lstBook.Add(book); } return lstBook; }
MogoDB查詢數據庫簡直不能太方便,不用做任何的操作,直接返回實體對象
public List<T> GetAll() { return collection.Find(_=>true).ToList(); }
對應以上結果:
1.使用NoSql的數據庫,非常的高效,非常的方便。
2.加了索引后,對於sqlsugar查詢效率提升太明顯。
3.不管是使用怎樣輕量級的ORM框架,效率都是趕不上寫原生sql的。
其他代碼片段:

/// <summary> /// MongoDb幫助類 /// </summary> public class MongoDB { private static readonly string connStr = "mongodb://127.0.0.1:27017"; private static readonly string dbName = "test"; private static IMongoDatabase db = null; private static readonly object lockHelper = new object(); private MongoDB() { } public static IMongoDatabase GetDb() { if (db == null) { lock (lockHelper) { if (db == null) { var client = new MongoClient(connStr); db = client.GetDatabase(dbName); } } } return db; } } public class MongoDbHelper<T> where T : BaseEntity { private IMongoDatabase db = null; private IMongoCollection<T> collection = null; public MongoDbHelper() { this.db = MongoDB.GetDb(); collection = db.GetCollection<T>(typeof(T).Name); } /// <summary> /// 新增 /// </summary> /// <param name="entity"></param> /// <returns></returns> public T Insert(T entity) { collection.InsertOne(entity); return entity; } /// <summary> /// 查詢所有數據 /// </summary> /// <returns></returns> public List<T> GetAll() { return collection.Find(_=>true).ToList(); } }

public class DbContext { string conn = "Data Source=10.101.98.197;port=3306;Initial Catalog=test;user id=test;password=123456;Charset=utf8;SslMode = none;"; public DbContext() { db = new SqlSugarClient(new ConnectionConfig() { ConnectionString = conn, DbType = SqlSugar.DbType.MySql, IsAutoCloseConnection = true }); } public SqlSugarClient db; } public class BookRepository : DbContext { public List<Book> GetAllBooks() { List<Book> list = db.Queryable<Book>().ToList(); return list; } public List<Tags> GetTagsByBooksId(string bookid) { return db.Queryable<Tags>().Where(x => x.BookId == bookid).ToList(); } public void Insert(Book book) { db.Insertable<Book>(book).ExecuteCommand(); db.Insertable<Tags>(book.Tags).ExecuteCommand(); } public List<VBook> GetAll() { //List<Book> lstBook = db.Queryable<Book>().ToList(); //foreach (var book in lstBook) //{ // book.Tags = db.Queryable<Tags>().Where(x => x.BookId == book.Guid).ToList(); //} //return lstBook; var lstBook = db.Queryable<Book, Tags>((bk, tg) => new object[] { JoinType.Left, bk.Guid == tg.BookId }).Select((bk, tg) => new VBook { Guid = bk.Guid, Author = bk.Author, Title = bk.Title, Description = bk.Description, Price = bk.Price, Tag = tg.Tag }).ToList(); return lstBook; } public List<Book> GetAllByAdo() { List<Book> lstBook = new List<Book>(); string conn = "Data Source=127.0.0.1;port=3306;Initial Catalog=test;user id=test;password=123456;Charset=utf8;SslMode = none;"; string sql = "select * from book a,tags b where a.Guid=b.BookId"; DataTable dt = MySql.Data.MySqlClient.MySqlHelper.ExecuteDataset(conn, sql).Tables[0]; foreach (DataRow dr in dt.Rows) { Book book = new Book { Guid = dr["Guid"].ToString(), Author = dr["Author"].ToString(), Title = dr["Title"].ToString(), Description = dr["Description"].ToString(), Price = decimal.Parse(dr["Price"].ToString()), Tags = new List<Tags>() { new Tags { Guid = dr["Guid1"].ToString(), BookId = dr["BookId"].ToString(), Tag = dr["Tag"].ToString() } } }; lstBook.Add(book); } return lstBook; } }
工具: