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

posted @ 2013-06-06 10:59  莱布尼茨  阅读(7546)  评论(137编辑  收藏  举报