【问题标题】:Entity Framework 6 DbSet AddRange vs IDbSet Add - How Can AddRange be so much faster?Entity Framework 6 DbSet AddRange vs IDbSet Add - AddRange 怎么能这么快?
【发布时间】:2017-04-26 20:11:05
【问题描述】:

我在家用计算机上使用 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()}");

晚上开始,下班回家后检查。结果是这样的:

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

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

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

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

【问题讨论】:

  • 这不是因为AddAddRange,而是因为Add 的版本为每个事件调用db.SaveChanges()。如果你把它移出循环,结果应该是相似的。

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


【解决方案1】:

正如 Jakub 回答的那样,在每个添加的实体之后调用 SaveChanges 并没有帮助。但是,即使将其移出,您仍然会遇到一些性能问题。这不会解决由 Add 方法引起的性能问题。

添加与添加范围

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

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

见:Entity Framework - Performance Add


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

可以获得非常接近 SqlBulkCopy 的性能。

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

(这个库不是免费的)

此库允许您一次保存多个实体,从而使您的代码更高效。支持所有批量操作:

  • 批量保存更改
  • 批量插入
  • 批量更新
  • 批量删除
  • 批量合并
  • 批量同步

例子:

// 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;
});

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-09-11
    • 1970-01-01
    • 1970-01-01
    • 2020-08-16
    • 1970-01-01
    • 2013-12-28
    • 1970-01-01
    • 2015-10-15
    相关资源
    最近更新 更多