实体框架大数据集,内存不足异常

本文关键字:内存不足 异常 数据集 框架 实体 | 更新日期: 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在上下文的整个生命周期中都会保存第二个集合,而这个集合会耗尽内存。

你有两个选项来处理这个

  1. 每批更新您的上下文
  2. 在查询中使用.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);
    }