第二十三节: EF性能篇(三)之基于开源组件 Z.EntityFrameWork.Plus.EF6解决EF性能问题
一. 開篇說明
EF的性能問題一直以來經(jīng)常被人所吐槽,究其原因在于“復雜的操作在生成SQL階段耗時長,且執(zhí)行效率不高”,但并不是沒有辦法解決,從EF本身舉幾個簡單的優(yōu)化例子:
①:如果僅是查詢數(shù)據(jù),并不對數(shù)據(jù)進行增、刪、改操作,查詢數(shù)據(jù)的時候可以取消狀態(tài)追蹤。
db.TestInfor.AsNoTracking().FirstOrDefault();②:用什么查什么,比如一張表有100多個字段,本次業(yè)務只需要5個字段,一定是select這5個字段,然后toList,而不是全部查詢,再toList()
③:利用EF調(diào)用原生SQL語句或者EF調(diào)用存儲過程執(zhí)行。 (目前為止,沒有發(fā)現(xiàn)該方式存在什么問題,而且性能也很快,廣大博友如果認為這種方式存在什么問題,可以留言給我普及掃盲一下)
以上的幾種方式,或許在一定程度上能解決一些問題,但面對大數(shù)據(jù)量的增、刪、改,還是心有力而力不足。
1. 前面的章節(jié)
前面的章節(jié)提到了Z.EntityFramework.Extensions?插件解決EF性能問題,該插件確實很nb,性能很高,而且功能很全,但是呵呵,天上沒有掉餡餅的好事,該插件是收費的,如果你公司不差錢,或者你是土豪,那么強烈推薦使用該插件,性能確實不錯,并且你可以直接右上角 x,不需要看該篇文章了^_^。
但往往現(xiàn)實是殘酷,窮人居多,這個時候就需要找免費的解決方案了,前面章節(jié)提到了?SqlBulkCopy?類(與EF沒有半毛錢關系),它可以實現(xiàn)增加操作,不得不說,它在處理大數(shù)據(jù)量的增加的時候,確實很出色!!!。
那么刪除和更新怎么辦呢?
答案是:可以借助?Z.EntityFrameWork.Plus.EF6?才解決。
2. 進入主題
Z.EntityFrameWork.Plus.EF6? 和?Z.EntityFramework.Extensions?是同一公司的產(chǎn)物,該插件支持的功能很多,比如 刪除、更新、緩存機制、過濾器等等,但唯獨沒有新增操作(都懂得,什么功能都有的話,他的兄弟?Z.EntityFramework.Extensions?怎么辦?)。
本章節(jié)僅介紹刪除和更新兩個最常用的功能。
該插件的幾點說明:?
①:僅支持EF5、EF6、EF Core,注意不同的版本對應該插件的后綴不同,該章節(jié)使用的是EF 6.2,所以對應?Z.EntityFrameWork.Plus.EF6?
②:官方號稱:Improve EF Performance by 2000%
③:可以通過Nuget進行安裝
④:文檔地址? ? :? http://entityframework-plus.net/batch-delete
GitHub地址:?https://github.com/zzzprojects/EntityFramework-Plus
?3. 數(shù)據(jù)庫準備
?
二.?刪除相關
1. Delete() 同步刪除方法
2. DeleteAsync() 異步刪除方法 <根據(jù)實際業(yè)務場景選擇使用>
3. BatchSize:批次大小
Delete和DeleteAsync兩個刪除方法都可以設置該參數(shù)的值:x => x.BatchSize,該參數(shù)表示一次執(zhí)行的條數(shù),默認值為4000,比如你要刪除4w條數(shù)據(jù),默認值的話,就要刪除10次,
適當?shù)奶岣咴撝?#xff0c;會增加刪除效率,但并不代表無限增大。
特別注意:下面測試使用的Delete方法是默認塊級大小4000的情況下進行測試,后面把BatchSize直接改為8w,刪除8w條數(shù)據(jù)在1.6s左右
4:BatchDelayInterval:批次執(zhí)行的時間間隔
比如BatchSize=4000,BatchDelayInterval=1000,刪除4w條數(shù)據(jù),表示的意思是刪除4000的時候等待1s,然后再刪除。
PS:該參數(shù)不是很常用,適用于你既需要刪除很多數(shù)據(jù),而且在批處理之間的暫停間隔繼續(xù)執(zhí)行CRUD操作
5:Executing:執(zhí)行刪除命令之前,去執(zhí)行一段命令文本
PS:根據(jù)實際場景選擇使用。
下面進行性能測試:(1w條、 4w條、?8w條數(shù)據(jù)的刪除操作)
?(1). EF原生刪除代碼
1 /// <summary>2 /// EF普通方法測試性能3 /// </summary>4 /// <param name="db"></param>5 public static void DeleteCommon1(DbContext db)6 {7 Console.WriteLine("---------------------調(diào)用普通方法1刪除--------------------------------");8 var list=db.Set<TestTwo>.Where(u=>u.id!="1").ToList(); 9 Stopwatch watch = Stopwatch.StartNew(); 10 foreach (var item in list) 11 { 12 db.Entry(item).State = EntityState.Deleted; 13 } 14 int count = db.SaveChanges(); 15 watch.Stop(); 16 Console.WriteLine($"{count}條數(shù)據(jù)耗時:{watch.ElapsedMilliseconds}"); 17 }?(2). EF調(diào)用SQL語句的代碼
1 /// <summary>2 /// EF調(diào)用SQL語句測試刪除3 /// </summary>4 /// <param name="db"></param>5 public static async void DeleteCommon2(DbContext db)6 {7 Stopwatch watch = Stopwatch.StartNew();8 string sql = "delete from TestTwo where id !='1' ";9 int count = 0; 10 //加上await,表示在這一步上異步方法執(zhí)行完 11 var response = await db.Database.ExecuteSqlCommandAsync(sql); 12 count = response; 13 Console.WriteLine("異步方法已經(jīng)開始執(zhí)行,請耐心等待"); 14 watch.Stop(); 15 Console.WriteLine($"{count}條數(shù)據(jù)耗時:{watch.ElapsedMilliseconds}"); 16 }(3). 利用該插件擴展的代碼
1 public static void DeletePlus(DbContext db)2 {3 Console.WriteLine("---------------------調(diào)用擴展方法刪除--------------------------------");4 Stopwatch watch = Stopwatch.StartNew();5 int count = db.Set<TestTwo>().Where(u => u.id != "1").Delete();6 //設置塊級大小(默認4000)7 //int count = db.Set<TestTwo>().Where(u => u.id != "1").Delete(u => u.BatchSize = 80000);8 watch.Stop();9 Console.WriteLine($"{count}條數(shù)據(jù)耗時:{watch.ElapsedMilliseconds}"); 10 }最終的測試結論(下面的時間是取三次結果的平均值):
1w條數(shù)據(jù) 4w條數(shù)據(jù) ? ? 8w條數(shù)據(jù)
EF原生刪除 ? ? ?76s? 累哭了 ? ? 累哭了
EF調(diào)SQL語句 ? ? 1.152s? ? ? ? 1.232s ? ?1.558s
Z.Plus(默認塊)? ? 1.307s? 1.982s? ?2.675s
最終結論:?Z.EntityFrameWork.Plus.EF6的刪除比EF原生要快的多! 但EF直接調(diào)用SQL語句貌似更快哈。
?
三. 更新相關
? 有了上面刪除的基礎,這里的更新操作就容易的多,更新的性能提升與刪除類似,這里不再單獨測試了,下面簡單粗暴,直接介紹用法。
1. Update() 同步更新方法
2. UpdateAsync() 異步更新方法
3. Executing:上述兩個方法的一個參數(shù),表示執(zhí)行更新命令之前,去執(zhí)行一段命令文本(根據(jù)實際情況選擇使用)
?直接上代碼:
1 public static void UpdatePlus(DbContext db)2 {3 Console.WriteLine("---------------------調(diào)用擴展方法更新--------------------------------");4 Stopwatch watch = Stopwatch.StartNew();5 int count = db.Set<TestTwo>().Where(u => u.id != "1").Update(x => new TestTwo()6 {7 t21 = "0",8 t22 = "1"9 }); 10 watch.Stop(); 11 Console.WriteLine($"{count}條數(shù)據(jù)耗時:{watch.ElapsedMilliseconds}"); 12 }?
綜述:該插件的使用非常簡單,在使用上,可以說沒有任何難度可言,很多情況下,并不是你不會解決,而是你缺少一雙善于發(fā)現(xiàn)的眼鏡。
免費的大數(shù)據(jù)解決方案: SqlBulkCopy +?Z.EntityFrameWork.Plus + EF調(diào)用SQL語句/存儲過程? ? ?或許是一個不錯的選擇。
?
總結
以上是生活随笔為你收集整理的第二十三节: EF性能篇(三)之基于开源组件 Z.EntityFrameWork.Plus.EF6解决EF性能问题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 黄金积存是什么?一文弄清
- 下一篇: 招商银行信用卡外币消费如何还款