Entity Framework數據插入性能追蹤


寫在開頭:本文的評論者大多認為我這個測試不對,但是哪里不對沒有誰給出一個明確的回復;對於若干純粹謾罵的評論(似乎我說EF性能低==侮辱了他全家),我已刪除。我的目的就是插入7千條數據到數據庫中,得出的結論是在數據Add到上下文這個階段比較耗時,如果有能繞過這個過程的方法,或者改進的建議,請提出,否則我不認為EF在這個場景中性能低下的結論是錯誤的!

為了不“激怒”更多人,標題都改了好幾次。當時寫這篇文章並不是為了證明什么,純粹是我在運行某項目的過程中“發現”了EF的某個瓶頸,遍尋解決方案未果,所以記錄下來。唉,怪只怪我太單純了……解決方法在文章最后。

另外關於在SaveChanges()時候會將生成的SQL語句一次性提交到數據庫的言論也可以消了,后面有部分評論持這個觀點,首先我一再強調瓶頸不在數據庫交互階段;為了避免類似無意義的評論反復出現,麻煩在吐槽之前用Profiler跟蹤一下。

早就聽說EF的性能不咋地,沒想到真的不咋地,而且還不是一般的不咋地(一句玩笑話引來一群人口誅筆伐,不明真相的博主表示很淡定)。有圖有真相,已經在項目中應用了EF的朋友慎入!

1、.NET4.0,EF4.4

 1 public void ExecRealTimeRun(List<RealTimeStocks> realTimeData)
 2 {
 3     using (var context = new StockDataEntities())
 4     {
 5         context.Database.ExecuteSqlCommand("delete from RealTimeStocks");
 6 
 7         var now1 = DateTime.Now.TimeOfDay;
 8         Console.WriteLine(string.Format("{0}開始將數據Add到上下文中,數據量:{1}", now1, realTimeData.Count));
 9         foreach (var data in realTimeData)
10         {
11             context.RealTimeStocks.Add(data);
12         }
13 
14         var now2 = DateTime.Now.TimeOfDay;
15         Console.WriteLine(string.Format("{0}數據Added完畢,開始執行Insert操作,耗時{1}", now2, now2 - now1));
16         try
17         {
18             context.SaveChanges();
19         }
20         catch (DbEntityValidationException dbEx)
21         { }
22         catch
23         { }
24 
25         var now3 = DateTime.Now.TimeOfDay;
26         Console.WriteLine(string.Format("{0}Insert完畢,耗時{1}", now3, now3 - now2));
27     }
28 }

很簡單,木有多余邏輯,結果:

插入7K多數據,超過1分鍾。反復測了幾次,結果相差不大,假如將SaveChanges操作包裹在TransactionScope中(純粹為了測試,看是不是更耗時),結果沒什么變化。

2、.NET4.5,EF4.4

聽說只要升級到.NET4.5,EF就會有性能上的提升,因為EF用到了.NET框架的某些類庫,隨着這些類庫的升級,EF也提高了性能。so,干巴爹。結果:

(這圖可以不用貼,因為和上圖沒什么兩樣)

3、.NET4.5,EF5.0

微軟跟我說5.0有67%的性能提升(有人說只是提高了查詢性能,這里側重調侃),我想這么大公司會亂說?於是卸載了4.4,安裝了5.0(貌似NuGet里,會根據你的.NET版本安裝相應版本的EF;但是你.NET升級后,EF不會跟着升級,也不能直接更新)。重新啟動測試,結果:

(這圖可以不用貼,因為和上圖沒什么兩樣)

4、其實么,關鍵不是在數據庫插入階段,而是在代碼層的Add階段,so,我並不認為和ADO.NET相比較有什么意義,因為ADO.NET沒有上下文,而低效點就是Add到上下文的過程(博主在這里明確表示,以下代碼是為了比較SaveChanges方法和ADO.NET的執行效率,而非整個插入階段的效率)有朋友評論說我Add的方式錯了,不知道應該怎么寫,請教。

無論如何,貼代碼吧:

 1 public void ExecRealTimeRunByADO(List<RealTimeStocks> realTimeData)
 2 {
 3     string insertText = @"insert [dbo].[RealTimeStocks]([Hqgpdm], [Hqzrsp], [Hqjrkp], [Hqzjcj], [Hqcjsl], [Hqdqcjsl],
 4 [Hqcjje], [Hqdqcjje], [Hqcjbs], [Hqzgcj], [Hqzdcj], [Hqsyl1], [Hqsyl2], [Hqjgsd1], [Hqjgsd2], [Hqhycc], [Hqsjw5], [Hqssl5], 
 5 [Hqsjw4], [Hqssl4], [Hqsjw3], [Hqssl3], [Hqsjw2], [Hqssl2], [Hqsjw1], [Hqssl1], [Hqbjw1], [Hqbsl1], [Hqbjw2], [Hqbsl2], 
 6 [Hqbjw3], [Hqbsl3], [Hqbjw4], [Hqbsl4], [Hqbjw5], [Hqbsl5], [HQTime], [UpdateTime], [ExponentRiseDown], [RiseDownPercent], 
 7 [ExponentSwing], [TimeID], [RiseNum], [DownNum], [EqualNum], [DataSource], [IsDeleted], [AddTime], [SMGUID])
 8 values ('{0}', {1}, {2}, {3}, {4}, null, {5}, null, null, {6}, {7}, {8}, null, {9}, {10}, null, {11}, {12}, {13}, {14}, {15}, 
 9 {16}, {17}, {18}, null, {19}, null, {20}, {21}, {22}, {23}, {24}, {25}, {26}, {27}, {28}, '{29}', '{30}', {31}, {32}, {33}, {34},
10 {35}, {36}, {37}, null, {38}, '{39}', '{40}')";
11     using (var context = new StockDataEntities())
12     {
13         context.Database.ExecuteSqlCommand("delete from RealTimeStocks");
14 
15         var now2 = DateTime.Now.TimeOfDay;
16         Console.WriteLine(string.Format("{0}開始執行Insert操作", now2));
17         using (TransactionScope scope = new TransactionScope(TransactionScopeOption.RequiresNew, new TimeSpan(0, 2, 0)))
18         {
19             try
20             {
21                 foreach (var data in realTimeData)
22                 {
23                     string cmd = string.Format(insertText, data.Hqgpdm, data.Hqzrsp, data.Hqjrkp, data.Hqzjcj, data.Hqcjsl,
24 data.Hqcjje, data.Hqzgcj, data.Hqzdcj, data.Hqsyl1, data.Hqjgsd1, data.Hqjgsd2, data.Hqsjw5, data.Hqssl5,
25 data.Hqsjw4, data.Hqssl4, data.Hqsjw3, data.Hqssl3, data.Hqsjw2, data.Hqssl2, data.Hqssl1, data.Hqbsl1, data.Hqbjw2, data.Hqbsl2,
26 data.Hqbjw3, data.Hqbsl3, data.Hqbjw4, data.Hqbsl4, data.Hqbjw5, data.Hqbsl5, data.HQTime, data.UpdateTime, data.ExponentRiseDown, data.RiseDownPercent,
27 data.ExponentSwing, data.TimeID, data.RiseNum, data.DownNum, data.EqualNum, data.IsDeleted ? 1 : 0, data.AddTime, data.SMGUID);
28                     context.Database.ExecuteSqlCommand(cmd);
29                 }
30                 scope.Complete();
31             }
32             catch
33             {
34                 Console.WriteLine("出錯");
35                 return;
36             }
37 
38             var now3 = DateTime.Now.TimeOfDay;
39             Console.WriteLine(string.Format("{0}Insert完畢,耗時{1}", now3, now3 - now2));
40         }
41     }
42 }

Insert語句我是直接拷貝EF動態生成的語句,稍微修改了下。使用的雖然不是正宗的ADO.NET,但是也差不多,你別跟我說EF的ExecuteSqlCommand用的是另一套東西。

結果:

不言自明(看來還有些人不明白,博主想說:SaveChanges並沒有多少性能損失)。

結論:坐等10.0版本!or context.Configuration.AutoDetectChangesEnabled = false!(thx to eflay && flytothemoon)

轉載請注明本文出處:http://www.cnblogs.com/newton/archive/2013/06/06/3120497.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM