Итерация через IQueryable с foreach приводит к исключению из памяти
Я перебираю небольшую (~10GB) таблицу с foreach / IQueryable и LINQ-to-SQL. Выглядит примерно так:
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. Я предполагаю, что строки dtable не очищаются. Что делать?
5 ответов
на IQueryable<DailyResult>
dtable попытается загрузить весь результат запроса в память при перечислении... перед любой итерации цикла foreach. Он не загружает одну строку во время итерации цикла foreach. Если вы хотите такое поведение, используйте DataReader.
вы называете ~10GB smallish? у тебя хорошее чувство юмора!
вы можете рассмотреть возможность загрузки строк в куски, он же разбиение на страницы.
conn.DailyResults.Where(dr => dr.DailyTransactionTypeID == 1).Skip(x).Take(y);
использование DataReader является шагом назад, если нет способа использовать его в LINQ. Я думал, мы пытаемся сбежать от АДО.
решение, предложенное выше, работает, но оно действительно уродливо. Вот мой код:
int iTake = 40000;
int iSkip = 0;
int iLoop;
ent.CommandTimeout = 6000;
while (true)
{
iLoop = 0;
IQueryable<viewClaimsBInfo> 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 записей. Не хороший.
Обновлено 6/10/2011: даже это не работает. В 2,000,000 записей или около того, я получаю из памяти исключение. Он также мучительно медленный. Когда я изменил его для использования OleDB, он работал примерно за 15 секунд (в отличие от 10+ минут) и не заканчивался. У кого-нибудь есть решение LINQ, которое работает и работает быстро?
использовать .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. :)
}
}