一. 開篇說明html
EF的性能問題一直以來常常被人所吐槽,究其緣由在於「複雜的操做在生成SQL階段耗時長,且執行效率不高」,但並非沒有辦法解決,從EF自己舉幾個簡單的優化例子:git
①:若是僅是查詢數據,並不對數據進行增、刪、改操做,查詢數據的時候能夠取消狀態追蹤。github
db.TestInfor.AsNoTracking().FirstOrDefault();
②:用什麼查什麼,好比一張表有100多個字段,本次業務只須要5個字段,必定是select這5個字段,而後toList,而不是所有查詢,再toList()sql
③:利用EF調用原生SQL語句或者EF調用存儲過程執行。 (目前爲止,沒有發現該方式存在什麼問題,並且性能也很快,廣大博友若是認爲這種方式存在什麼問題,能夠留言給我普及掃盲一下)數據庫
以上的幾種方式,或許在必定程度上能解決一些問題,但面對大數據量的增、刪、改,仍是心有力而力不足。緩存
1. 前面的章節異步
前面的章節提到了Z.EntityFramework.Extensions 插件解決EF性能問題,該插件確實很nb,性能很高,並且功能很全,可是呵呵,天上沒有掉餡餅的好事,該插件是收費的,若是你公司不差錢,或者你是土豪,那麼強烈推薦使用該插件,性能確實不錯,而且你能夠直接右上角 x,不須要看該篇文章了^_^。
async
但每每現實是殘酷,窮人居多,這個時候就須要找免費的解決方案了,前面章節提到了 SqlBulkCopy 類(與EF沒有半毛錢關係),它能夠實現增長操做,不得不說,它在處理大數據量的增長的時候,確實很出色!!!。post
那麼刪除和更新怎麼辦呢? 性能
答案是:能夠藉助 Z.EntityFrameWork.Plus.EF6 才解決。
2. 進入主題
Z.EntityFrameWork.Plus.EF6 和 Z.EntityFramework.Extensions 是同一公司的產物,該插件支持的功能不少,好比 刪除、更新、緩存機制、過濾器等等,但惟獨沒有新增操做(都懂得,什麼功能都有的話,他的兄弟 Z.EntityFramework.Extensions 怎麼辦?)。
本章節僅介紹刪除和更新兩個最經常使用的功能。
該插件的幾點說明:
①:僅支持EF五、EF六、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 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}條數據耗時:{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詳解(持續更新)
!