• "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("订单开始:
    ");
      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;

    下面来看看禁用以后的执行速度:

    QQ截图20130607002820

    另外一个解决办法就是使用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();

    QQ截图20130607004003

    AddRange方法在System.Data.Entity 泛型DbSet类中,下图是我通过Reflector截的图

    QQ截图20130607004407

    QQ截图20130607004652

    从上面两幅图中可以看到,Add和AddRange都是添加到_internalSet中,但是如果AutoDetectChangesEnabled设置为true的话,添加任何实体之前都会调用DetectChanges,注意看Remarks中的解释。

    测试源码下载地址:http://www.ef-community.com/forum.php?mod=viewthread&tid=437&extra=page%3D1

  • 相关阅读:
    重写jQuery serialize方法,使文本框在没有输入的情况下,使用其支持默认值
    跟我一起,利用bitcms内容管理系统从0到1学习小程序开发:三、上传图片到服务器
    跟我一起,利用bitcms内容管理系统从0到1学习小程序开发:二、与服务端通信,Hello bitcms!
    跟我一起,利用bitcms内容管理系统从0到1学习小程序开发:一、IIS下SSL环境搭建
    bitcms 一个迟到的项目,一个老程序的项目总结
    设置一周每天所占的百分比特效,可拖,可填,可回车
    jquery中的uploadfile关于图片上上传的插件的应用
    jQuery中的.live()与die()
    Java 遍历文件下jpg图片并解析图片
    Cookie已经过时,细看Facebook, Google, Apple如何追踪用户
  • 原文地址:https://www.cnblogs.com/lenther2002/p/4829321.html
Copyright © 2020-2023  润新知