"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;

下面來看看禁用以后的執行速度:

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

 

夜已深!

天亮了,就要高考了,祝福所有的考生!

Technorati 標簽: EF, EntityFramework, DetectChanges


免責聲明!

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



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