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

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

容易 相關 aps 20px pwa ges ren 安裝 官方

一. 開篇說明

  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性能問題