使用foreach迭代IQueryable会导致内存不足exception

我正在使用foreach / IQueryable和LINQ-to-SQL迭代一个小的(~10GB)表。 看起来像这样:

using (var conn = new DbEntities() { CommandTimeout = 600*100}) { var dtable = conn.DailyResults.Where(dr => dr.DailyTransactionTypeID == 1); foreach (var dailyResult in dtable) { //Math here, results stored in-memory, but this table is very small. //At the very least compared to stuff I already have in memory. :) } } 

Visual Studio调试器在foreach循环的基础上短暂地抛出一个内存不足exception。 我假设dtable的行没有被刷新。 该怎么办?

IQueryable dtable将尝试在枚举循环的任何迭代之前枚举时将整个查询结果加载到内存中。 它在foreach循环的迭代期间不加载一行。 如果您需要该行为,请使用DataReader 。

你打电话~10GB小? 你有一种很好的幽默感!

您可以考虑以块(也称为分页)加载行。

 conn.DailyResults.Where(dr => dr.DailyTransactionTypeID == 1).Skip(x).Take(y); 

使用DataReader是向后退一步,除非有一种方法可以在LINQ中使用它。 我以为我们试图摆脱ADO。

上面提出的解决方案有效,但它真的很难看。 这是我的代码:

 int iTake = 40000; int iSkip = 0; int iLoop; ent.CommandTimeout = 6000; while (true) { iLoop = 0; IQueryable iInfo = (from q in ent.viewClaimsBInfo where q.WorkDate >= dtStart && q.WorkDate <= dtEnd orderby q.WorkDate select q) .Skip(iSkip).Take(iTake); foreach (viewClaimsBInfo qInfo in iInfo) { iLoop++; if (lstClerk.Contains(qInfo.Clerk.Substring(0, 3))) { /// Various processing.... } } if (iLoop < iTake) break; iSkip += iTake; } 

您可以看到我必须检查是否已用完记录,因为foreach循环将以40,000条记录结束。 不好。

Updated 6/10/2011:即使这样也行不通。 在2,000,000条左右的记录中,我得到了一个内存不足的exception。 它也极其缓慢。 当我修改它以使用OleDB时,它运行大约15秒(而不是10分钟以上)并且没有内存耗尽。 有没有人有LINQ解决方案可以运行并快速运行?

我建议使用SQL来修改这些数据。

使用.AsNoTracking() – 它告诉DbEntities 不要缓存检索到的行

 using (var conn = new DbEntities() { CommandTimeout = 600*100}) { var dtable = conn.DailyResults .AsNoTracking() // <<<<<<<<<<<<<< .Where(dr => dr.DailyTransactionTypeID == 1); foreach (var dailyResult in dtable) { //Math here, results stored in-memory, but this table is very small. //At the very least compared to stuff I already have in memory. :) } }