遍历大型数据集时出现OutOfMemoryException异常

3
我有一个大约有10万行的表格(而且它将会变得更大)。目前我的代码在循环到第80000条记录时抛出了一个OutOfMemoryException异常(即使此时我的系统有超过10GB的可用空间,看起来Visual Studio只能使用约1.5GB)。
这段代码旨在循环遍历所有记录并检查某些条件。我已经注释掉了实际处理记录的代码,但内存仍然被占满了。
using (var db = new PlaceDBContext())
{
    Messages.Output("Total: " + db.Companies.Count());
    int count = 0;
    foreach (var company in db.Companies)
    {

        // I am not actually doing anything here,
        // I took out my code and the memory still fills up
        // CheckMatchConditions(company);

        count++;

        Console.SetCursorPosition(0, Console.CursorTop);
        Console.Write(count.ToString() + "          ");

    }

}

我认为这可能与保持上下文开放有关,因此我重构了代码,只取1000条记录,并首先将它们全部枚举到一个列表中。以下是我想出来的代码:

int count = 0;
int total = 0;
using (var db = new PlaceDBContext())
{
    Messages.Output("Total: " + db.Companies.Count());
    total = db.Companies.Count();
}
while (count < total)
{
    List<Company> toMatch = new List<Company>();
    using (var db = new PlaceDBContext())
    {
        toMatch = db.Companies.Include(x => x.CompaniesHouseRecords).OrderBy(x => x.ID).Skip(count).Take(1000).ToList();
    }

    foreach (var company in toMatch)
    {

        // CheckMatchConditions(company);

        count++;

        Console.SetCursorPosition(0, Console.CursorTop);
        Console.Write(count.ToString() + "          ");

    }
}

这样做虽然速度较慢,但仍以大约相同的记录循环速率填充内存。

由于我注释掉了实际执行操作的方法,所以可能只是这些 toMatch 列表停留在内存中。

我不知道该怎样管理内存,请问有人能解决这个问题吗?


你能把你的匹配条件转换成where条件吗?就像db.Companies.Where(CheckMatchConditions)这样。另外,你想以某种方式处理对象吗?如果是这样,怎么处理? - DolphinSX
2个回答

3
添加 .AsNoTracking() 方法可以确保 DbContext 不会跟踪实体。
using (var db = new PlaceDBContext())
{
    Messages.Output("Total: " + db.Companies.Count());
    int count = 0;
    foreach (var company in db.Companies.AsNoTracking())
    {
        count++;
        Console.SetCursorPosition(0, Console.CursorTop);
        Console.Write(count.ToString() + ". company : " + company.someProp);
    }
}

1
完美!现在内存不会超过60MB了。 - Guerrilla

0

不要遍历对象集合,因为 EF 在将实体选择为对象后会跟踪更改。 请通过一些 DTO 进行迭代。

db.Companies.Select(c => new CompanyDto{ Name = c.Name});

但最好不要遍历整个数据集合。尝试使用LINQ编写您的检查条件方法,以允许SQL服务器进行过滤。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接