第二十三節: EF性能篇(三)之基於開源組件 Z.EntityFrameWork.Plus.EF6解決EF性能問題

一. 開篇說明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詳解(持續更新)

 

 

 

 

!

  • 做       者 : Yaopengfei(姚鵬飛)
  • 博客地址 : http://www.cnblogs.com/yaopengfei/
  • 聲     明1 : 本人才疏學淺,用郭德綱的話說「我是一個小學生」,若有錯誤,歡迎討論,請勿謾罵^_^。
  • 聲     明2 : 原創博客請在轉載時保留原文連接或在文章開頭加上本人博客地址,如需代碼請留下你的評論,加我QQ:604649488 (備註:評論的博客名)
相關文章
相關標籤/搜索