"Entity Framework数据插入性能追踪"读后总结
园友莱布尼茨写了一篇《Entity Framework数据插入性能追踪》的文章,我感觉不错,至少他提出了问题,写了出来,引起了大家的讨论,这就是一个氛围。读完文章+评论,于是我自己也写了个简单的程序试了试。
先晒一下代码:
两个简单的类:
1: /// <summary>
2: /// 消费者
3: /// </summary>
4: public class Consumer
5: {
6: public int CId { get; set; }
7: public string CName { get; set; }
8: public List<Order> Orders { get; set; }
9: }
10:
11: /// <summary>
12: /// 订单
13: /// </summary>
14: public class Order
15: {
16: public int OrderNo { get; set; }
17: public DateTime OrderDate { get; set; }
18: public decimal TotalMoney { get; set; }
19: public int CId { get; set; }
20:
21: public Consumer Consumer { get; set; }
22: }
映射配置:
1: public class ConsumerConfiguration : EntityTypeConfiguration<Consumer>
2: {
3: public ConsumerConfiguration()
4: {
5: HasKey(t => t.CId).Property(t => t.CId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
6: Property(t => t.CName).IsRequired().HasMaxLength(50);
7: }
8: }
9:
10: public class OrderConfiguration : EntityTypeConfiguration<Order>
11: {
12: public OrderConfiguration()
13: {
14: HasKey(t => t.OrderNo);
15: HasRequired(t => t.Consumer).WithMany(t => t.Orders).HasForeignKey(t => t.CId);
16: }
17: }
Context:
1: public class TestContext : DbContext
2: {
3: public DbSet<Consumer> Consumers { get; set; }
4: public DbSet<Order> Orders { get; set; }
5:
6: protected override void OnModelCreating(DbModelBuilder modelBuilder)
7: {
8: modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
9:
10: modelBuilder.Configurations.Add(new ConsumerConfiguration());
11: modelBuilder.Configurations.Add(new OrderConfiguration());
12:
13: base.OnModelCreating(modelBuilder);
14: }
15: }
测试代码:
1: static void Main(string[] args)
2: {
3: using (var ctx = new TestContext())
4: {
5: ctx.Consumers.Add(new Consumer()
6: {
7: CName = "张三"
8: });
9: ctx.SaveChanges();
10:
11: Stopwatch sw = new Stopwatch();
12: sw.Start();
13: Console.WriteLine("订单开始:\n");
14:
15: for (int outer = 0; outer < 20000; outer++)
16: {
17: ctx.Orders.Add(new Order()
18: {
19: OrderDate = DateTime.Now,
20: TotalMoney = 100,
21: CId = 1,
22: });
23: }
24: ctx.SaveChanges();
25: sw.Stop();
26: Console.WriteLine(sw.Elapsed.Minutes + "分" + sw.Elapsed.Seconds + "秒" + sw.Elapsed.Milliseconds + "毫秒");
27: }
28: }
上面的代码是最平常的代码了,没有什么可解释的,将内容放到重点上。
运行以上代码的环境是VS2012+SQL SERVER 2008 R2,机器配置:4G,N年以前的CPU。
运行上面的代码非常的慢,正如莱布尼茨说的,在数据Add到上下文这个阶段比较耗时。出现这个问题的原因是:每次调用ctx.Orders.Add(order)之前,EF都会调用DetectChanges,在StackOverFlow上有解释,地址是:http://stackoverflow.com/questions/9439430/improving-performance-of-initializing-dbset-in-seed,另外在Programming Entity Framework DbContext这本书的60也有DetectChange的介绍。
解决上面速度慢的问题的办法就是设置
1: ctx.Configuration.AutoDetectChangesEnabled = false;
下面来看看禁用以后的执行速度:
另外一个解决办法就是使用DbSet<T>.AddRange方法,这个方法是在6.0 beta1中加入的。
1: List<Order> orderList = new List<Order>();
2: for (int outer = 0; outer < 20000; outer++)
3: {
4: orderList.Add(new Order()
5: {
6: OrderDate = DateTime.Now,
7: TotalMoney = 100,
8: CId = 1
9: });
10: }
11: ctx.Orders.AddRange(orderList);
12: ctx.SaveChanges();
AddRange方法在System.Data.Entity 泛型DbSet类中,下图是我通过Reflector截的图
从上面两幅图中可以看到,Add和AddRange都是添加到_internalSet中,但是如果AutoDetectChangesEnabled设置为true的话,添加任何实体之前都会调用DetectChanges,注意看Remarks中的解释。
测试源码下载地址:http://www.ef-community.com/forum.php?mod=viewthread&tid=437&extra=page%3D1
夜已深!
天亮了,就要高考了,祝福所有的考生!
作者:程序旅途
出处:https://www.cnblogs.com/nianming/archive/2013/06/07/3123103.html
版权:本站使用「CC BY 4.0」创作共享协议,转载请在文章明显位置注明作者及出处。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?