我正在家用电脑上玩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
查询但是解释代码中的内容会很好。
答案 0 :(得分:10)
正如Jakub回答的那样,在每个添加的实体都没有帮助之后调用SaveChanges。但即使你把它移出去,你仍会遇到一些性能问题。这不会解决Add方法导致的性能问题。
使用Add方法添加多个实体是一个非常常见的错误。事实上,它是 INSANELY 慢的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;
});