【发布时间】:2021-03-26 08:03:01
【问题描述】:
我有一个长时间运行的应用程序,它下载一些数据并将它们批量插入到 sql server 数据库中。
我已禁用跟踪并设置AutoDetectChangesEnabled = false
_context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
_context.ChangeTracker.AutoDetectChangesEnabled = false;
while ((data = getData()) != null)
{
await _context.MyTable.AddRangeAsync(data);
await _context.SaveChangesAsync();
}
此代码开始快速插入数据,但几个小时后,我可以看到长时间的停顿并且使用的内存增长(许多 GB)。我怀疑 EF 核心在内存中保存了一份数据。
有什么方法可以禁用此行为?
我用这个原始的 sql 代码替换了在一个命令中插入多个项目并且内存根本没有增加。
while ((data = getData()) != null)
{
string cmd = $"INSERT INTO dbo.Table(name1,name2) VALUES "
+ string.Join(",", data.Select(x => $"('{x.name1}', '{x.name2}')"));
_context.Database.ExecuteSqlRaw(cmd);
}
我想使用非原始版本,但我是否遗漏了一些关于内存的内容?
【问题讨论】:
-
EF Contexts 将每个实体添加到上下文中,因此上下文分配的内存变得更大。在批量插入场景中,建议分批工作,处理和重新创建上下文。此外,您可以使用一些第三方批量插入 nuget 包。他们通常在内部使用纯 SQL 来进行插入,但效果很好,而且对您来说它是透明的。
-
@Pepelui360 谢谢,我希望有一些设置'不要让每个实体都添加到上下文中'。
-
在我切换到 Linq2db 之前,我也遇到了这个问题。 Linq2db 比 EFCore 更快更好的内存管理。
标签: c# performance entity-framework-core bulkinsert