第二十三節: EF性能篇(三)之基於開源組件 Z.EntityFrameWork.Plus.EF6解決EF性能問題
一. 開篇說明
EF的性能問題一直以來經常被人所吐槽,究其原因在於“復雜的操作在生成SQL階段耗時長,且執行效率不高”,但並不是沒有辦法解決,從EF本身舉幾個簡單的優化例子:
①:如果僅是查詢數據,並不對數據進行增、刪、改操作,查詢數據的時候可以取消狀態追蹤。
db.TestInfor.AsNoTracking().FirstOrDefault();
②:用什麽查什麽,比如一張表有100多個字段,本次業務只需要5個字段,一定是select這5個字段,然後toList,而不是全部查詢,再toList()
③:利用EF調用原生SQL語句或者EF調用存儲過程執行。 (目前為止,沒有發現該方式存在什麽問題,而且性能也很快,廣大博友如果認為這種方式存在什麽問題,可以留言給我普及掃盲一下
以上的幾種方式,或許在一定程度上能解決一些問題,但面對大數據量的增、刪、改,還是心有力而力不足。
1. 前面的章節
前面的章節提到了Z.EntityFramework.Extensions 插件解決EF性能問題,該插件確實很nb,性能很高,而且功能很全,但是呵呵,天上沒有掉餡餅的好事,該插件是收費的,如果你公司不差錢,或者你是土豪,那麽強烈推薦使用該插件,性能確實不錯,並且你可以直接右上角 x,不需要看該篇文章了^_^。
但往往現實是殘酷,窮人居多,這個時候就需要找免費的解決方案了,前面章節提到了 SqlBulkCopy 類(與EF沒有半毛錢關系),它可以實現增加和更新
那麽刪除和更新怎麽辦呢?
答案是:可以借助 Z.EntityFrameWork.Plus.EF6 才解決。
2. 進入主題
Z.EntityFrameWork.Plus.EF6 和 Z.EntityFramework.Extensions 是同一公司的產物,該插件支持的功能很多,比如 刪除、更新、緩存機制、過濾器等等,但唯獨沒有新增操作(都懂得,什麽功能都有的話,他的兄弟 Z.EntityFramework.Extensions 怎麽辦?)。
本章節僅介紹刪除和更新兩個最常用的功能。
該插件的幾點說明:
①:僅支持EF5、EF6、EF Core,註意不同的版本對應該插件的後綴不同,該章節使用的是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. 數據庫準備
二. 刪除相關
1. Delete() 同步刪除方法
2. DeleteAsync() 異步刪除方法 <根據實際業務場景選擇使用>
3. BatchSize:批次大小
Delete和DeleteAsync兩個刪除方法都可以設置該參數的值:x => x.BatchSize,該參數表示一次執行的條數,默認值為4000,比如你要刪除4w條數據,默認值的話,就要刪除10次,
適當的提高該值,會增加刪除效率,但並不代表無限增大。
特別註意:下面測試使用的Delete方法是默認塊級大小4000的情況下進行測試,後面把BatchSize直接改為8w,刪除8w條數據在1.6s左右
4:BatchDelayInterval:批次執行的時間間隔
比如BatchSize=4000,BatchDelayInterval=1000,刪除4w條數據,表示的意思是刪除4000的時候等待1s,然後再刪除。
PS:該參數不是很常用,適用於你既需要刪除很多數據,而且在批處理之間的暫停間隔繼續執行CRUD操作
5:Executing:執行刪除命令之前,去執行一段命令文本
PS:根據實際場景選擇使用。
下面進行性能測試:(1w條、 4w條、 8w條數據的刪除操作)
(1). EF原生刪除代碼
1 /// <summary> 2 /// EF普通方法測試性能 3 /// </summary> 4 /// <param name="db"></param> 5 public static void DeleteCommon1(DbContext db) 6 { 7 Console.WriteLine("---------------------調用普通方法1刪除--------------------------------"); 8 Stopwatch watch = Stopwatch.StartNew(); 9 var list = db.Set<TestTwo>().Where(u => u.id != "1").ToList(); 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}條數據耗時:{watch.ElapsedMilliseconds}"); 17 }
(2). EF調用SQL語句的代碼
1 /// <summary> 2 /// EF調用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,表示在這一步上異步方法執行完 11 var response = await db.Database.ExecuteSqlCommandAsync(sql); 12 count = response; 13 Console.WriteLine("異步方法已經開始執行,請耐心等待"); 14 watch.Stop(); 15 Console.WriteLine($"{count}條數據耗時:{watch.ElapsedMilliseconds}"); 16 }
(3). 利用該插件擴展的代碼
1 public static void DeletePlus(DbContext db) 2 { 3 Console.WriteLine("---------------------調用擴展方法刪除--------------------------------"); 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}條數據耗時:{watch.ElapsedMilliseconds}"); 10 }
最終的測試結論(下面的時間是取三次結果的平均值):
1w條數據 4w條數據 8w條數據
EF原生刪除 76s 累哭了 累哭了
EF調SQL語句 1.152s 1.232s 1.558s
Z.Plus(默認塊) 1.307s 1.982s 2.675s
最終結論: Z.EntityFrameWork.Plus.EF6的刪除比EF原生要快的多! 但EF直接調用SQL語句貌似更快哈。
三. 更新相關
有了上面刪除的基礎,這裏的更新操作就容易的多,更新的性能提升與刪除類似,這裏不再單獨測試了,下面簡單粗暴,直接介紹用法。
1. Update() 同步更新方法
2. UpdateAsync() 異步更新方法
3. Executing:上述兩個方法的一個參數,表示執行更新命令之前,去執行一段命令文本(根據實際情況選擇使用)
直接上代碼:
1 public static void UpdatePlus(DbContext db) 2 { 3 Console.WriteLine("---------------------調用擴展方法更新--------------------------------"); 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}條數據耗時:{watch.ElapsedMilliseconds}"); 12 }
綜述:該插件的使用非常簡單,在使用上,可以說沒有任何難度可言,很多情況下,並不是你不會解決,而是你缺少一雙善於發現的眼鏡。
免費的大數據解決方案: SqlBulkCopy + Z.EntityFrameWork.Plus + EF調用SQL語句/存儲過程 或許是一個不錯的選擇。
如果你對EF感興趣,可以關註該章節:ORM系列之Entity FrameWork詳解(持續更新)
!
- 作 者 : Yaopengfei(姚鵬飛)
- 博客地址 : http://www.cnblogs.com/yaopengfei/
- 聲 明1 : 本人才疏學淺,用郭德綱的話說“我是一個小學生”,如有錯誤,歡迎討論,請勿謾罵^_^。
- 聲 明2 : 原創博客請在轉載時保留原文鏈接或在文章開頭加上本人博客地址,如需代碼請留下你的評論,加我QQ:604649488 (備註:評論的博客名)
第二十三節: EF性能篇(三)之基於開源組件 Z.EntityFrameWork.Plus.EF6解決EF性能問題