实体框架6 DbSet AddRange vs IDbSet Add - AddRange如何更快?

时间:2017-04-26 20:11:05

标签: c# entity-framework entity-framework-6

我正在家用电脑上玩Entity Framework 6,并决定尝试插入相当多的行,大约430k。

我的第一次尝试看起来像这样,是的,我知道它可能会更好,但无论如何都是为了研究:

var watch = System.Diagnostics.Stopwatch.StartNew();
foreach (var event in group)
{
    db.Events.Add(event);
    db.SaveChanges();
}

var dbCount = db.Events.Count(x => x.ImportInformation.FileName == group.Key);

if (dbCount != group.Count())
{
    throw new Exception("Mismatch between rows added for file and current number of rows!");
}

watch.Stop();
Console.WriteLine($"Added {dbCount} events to database in {watch.Elapsed.ToString()}");

晚上开始工作,当我下班回家时检查一下。这就是结果:

enter image description here

正如你所看到的,在前4小时41分钟内增加了64523个事件,但随后它变慢了很多,接下来的66985个事件花了14小时51分钟。我检查了数据库,程序仍在以极低的速度插入事件。然后我决定尝试DbSet的“新”AddRange方法。

我将模型从IDbSet切换为DbSet,并将foreach循环替换为:

db.Events.AddRange(group);
db.SaveChanges();

enter image description here

我现在可以在30秒左右添加60k +事件。这可能不是SqlBulkCopy快,但它仍然是一个巨大的进步。为实现这一目标,幕后发生了什么?我以为我明天会查询SQL Server Profiler查询但是解释代码中的内容会很好。

1 个答案:

答案 0 :(得分:10)

正如Jakub回答的那样,在每个添加的实体都没有帮助之后调用SaveChanges。但即使你把它移出去,你仍会遇到一些性能问题。这不会解决Add方法导致的性能问题。

添加与AddRange

使用Add方法添加多个实体是一个非常常见的错误。事实上,它是 INSANELY 慢的DetectChanges方法。

  • 添加每条记录后添加方法DetectChanges。
  • 添加所有记录后的AddRange方法DetectChanges。

请参阅:Entity Framework - Performance Add

  

它可能不是SqlBulkCopy快,但它仍然是一个巨大的改进

可以使性能非常接近SqlBulkCopy。

免责声明:我是该项目的所有者Entity Framework Extensions

(此库不是免费的)

通过允许您一次保存多个实体,此库可以提高您的代码效率。支持所有批量操作:

  • BulkSaveChanges
  • BulkInsert
  • BulkUpdate
  • BulkDelete
  • BulkMerge
  • BulkSynchronize

示例:

// Easy to use
context.BulkSaveChanges();

// Easy to customize
context.BulkSaveChanges(bulk => bulk.BatchSize = 100);

// Perform Bulk Operations
context.BulkDelete(customers);
context.BulkInsert(customers);
context.BulkUpdate(customers);

// Customize Primary Key
context.BulkMerge(customers, operation => {
   operation.ColumnPrimaryKeyExpression = 
        customer => customer.Code;
});