C# 实体框架6 DbSet AddRange与IDbSet Add-AddRange怎么能快这么多?
我在家用电脑上玩EntityFramework6,决定尝试插入相当多的行,大约430k 我的第一次尝试看起来是这样的,是的,我知道它可以更好,但无论如何它是为了研究:C# 实体框架6 DbSet AddRange与IDbSet Add-AddRange怎么能快这么多?,c#,entity-framework,entity-framework-6,C#,Entity Framework,Entity Framework 6,我在家用电脑上玩EntityFramework6,决定尝试插入相当多的行,大约430k 我的第一次尝试看起来是这样的,是的,我知道它可以更好,但无论如何它是为了研究: var watch = System.Diagnostics.Stopwatch.StartNew(); foreach (var event in group) { db.Events.Add(event); db.SaveChanges(); } var dbCount = db.Events.Count(x
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的“新”方法
我将我的模型从IDbSet
切换到DbSet
,并用以下内容替换foreach
循环:
db.Events.AddRange(group);
db.SaveChanges();
我现在可以在大约30秒内添加60k+个事件。这也许并不快,但仍然是一个巨大的进步。为了实现这一目标,发动机罩下发生了什么?我原以为明天我会检查SQL Server Profiler以获取查询,但最好能解释一下代码中发生了什么。正如Jakub回答的那样,在每个添加的实体都无效后调用SaveChanges。但是,即使您将其移出,您仍然会遇到一些性能问题。这将不会修复Add方法引起的性能问题 添加vs添加范围 使用Add方法添加多个实体是一个非常常见的错误。事实上,DetectChanges方法的速度非常慢
- Add方法在添加每个记录后检测更改
- AddRange方法在添加所有记录后检测更改
它可能不快,但仍然是一个巨大的改进 可以使性能非常接近SqlBulkCopy 免责声明:我是项目的所有者 (这个图书馆不是免费的) 该库允许您一次保存多个实体,从而使您的代码更加高效。支持所有批量操作:
- 批量保存更改
- 隔板
- 批量更新
- 批量删除
- 大合并
- 批量同步
// 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;
});
这不是因为
Add
或AddRange
,而是因为带有Add
的版本正在为每个事件调用db.SaveChanges()
。如果将其移出循环,结果应该类似。