实体框架大数据集,内存不足异常
本文关键字:内存不足 异常 数据集 框架 实体 | 更新日期: 2023-09-27 18:27:16
我正在处理一个非常大的数据集,大约有200万条记录。我有下面的代码,但在处理了大约三个批次,大约600000条记录后,出现了内存不足的异常。我理解,当它在每个批处理实体框架中循环时,惰性负载,然后试图将全部200万条记录构建到内存中。有没有办法把我处理过的那批货卸下来?
ModelContext dbContext = new ModelContext();
IEnumerable<IEnumerable<Town>> towns = dbContext.Towns.OrderBy(t => t.TownID).Batch(200000);
foreach (var batch in towns)
{
SearchClient.Instance.IndexMany(batch, SearchClient.Instance.Settings.DefaultIndex, "Town", new SimpleBulkParameters() { Refresh = false });
}
注意:Batch方法来自此项目:https://code.google.com/p/morelinq/
搜索客户端是这样的:https://github.com/Mpdreamz/NEST
问题是,当您从EF获取数据时,实际上创建了两个数据副本,一个返回给用户,另一个保留并用于更改检测(这样它就可以将更改持久化到数据库)。EF在上下文的整个生命周期中都会保存第二个集合,而这个集合会耗尽内存。
你有两个选项来处理这个
- 每批更新您的上下文
-
在查询中使用.AsNoTracking(),例如:
IEnumerable<IEnumerable<Town>> towns = dbContext.Towns.AsNoTracking().OrderBy(t => t.TownID).Batch(200000);
这个命令告诉EF不要保留一个拷贝用于变更检测。你可以在我的博客上阅读更多关于AsNoTracking的功能及其对性能的影响:http://blog.staticvoid.co.nz/2012/4/2/entity_framework_and_asnotracking
我编写了一个迁移例程,从一个数据库中读取并写入(布局略有变化)到另一个数据库(不同类型)中,在这种情况下,为每个批更新连接并使用AsNoTracking()并不能帮我解决问题。
请注意,使用'97版本的JET时会出现此问题。它可以与其他数据库完美地配合使用。
然而,以下算法确实解决了内存不足的问题:
- 使用一个连接进行读取,一个连接用于写入/更新
- 使用AsNoTracking()读取
-
每写入/更新50行左右,检查内存使用情况,根据需要恢复内存+重置输出DB上下文(和连接的表):
var before = System.Diagnostics.Process.GetCurrentProcess().VirtualMemorySize64; if (before > 800000000) { dbcontextOut.SaveChanges(); dbcontextOut.Dispose(); GC.Collect(); GC.WaitForPendingFinalizers(); dbcontextOut = dbcontextOutFunc(); tableOut = Dynamic.InvokeGet(dbcontextOut, outputTableName); }