Прочитайте огромную таблицу с LINQ to SQL: Недостаточно памяти против медленной подкачки

У меня есть огромная таблица, которую мне нужно прочитать в определенном порядке и вычислить статистику. Таблица уже имеет кластеризованный индекс для правильного порядка, поэтому получение самих записей происходит довольно быстро. Я пытаюсь использовать LINQ to SQL, чтобы упростить код, который мне нужно написать. Проблема в том, что я не хочу загружать все объекты в память, так как DataContext, кажется, удерживает их в памяти - но попытка их разметки приводит к ужасным проблемам с производительностью.

Вот поломка. Первоначальная попытка была такая:

var logs = 
    (from record in dataContext.someTable 
     where [index is appropriate]
     select record);

foreach( linqEntity l in logs )
{
    // Do stuff with data from l
}

Это довольно быстро и потоковое вещание с хорошей скоростью, но проблема в том, что использование памяти приложением постоянно увеличивается. Я предполагаю, что сущности LINQ to SQL хранятся в памяти и не располагаются должным образом. Итак, после прочтенияНедостаточно памяти при создании большого количества объектов C # Я попробовал следующий подход. Это кажется общимSkip/Take парадигма, которую используют многие люди, с добавленной функцией сохранения памяти.

Обратите внимание, что_conn создается заранее, и для каждого запроса создается временный контекст данных, в результате чего связанные сущности собираются мусором.

int skipAmount = 0;
bool finished = false;

while (!finished)
{
    // Trick to allow for automatic garbage collection while iterating through the DB
    using (var tempDataContext = new MyDataContext(_conn) {CommandTimeout = 600})
    {               
        var query =
            (from record in tempDataContext.someTable
             where [index is appropriate]
             select record);

        List<workerLog> logs = query.Skip(skipAmount).Take(BatchSize).ToList();
        if (logs.Count == 0)
        {
            finished = true;
            continue;
        }

        foreach( linqEntity l in logs )
        {
            // Do stuff with data from l
        }

        skipAmount += logs.Count;
    }
}

Теперь у меня есть желаемое поведение, при котором использование памяти вообще не увеличивается, когда я выполняю потоковую передачу данных. Тем не менее, у меня проблема гораздо хуже: каждыйSkip приводит к тому, что данные загружаются все медленнее и медленнее, так как базовый запрос фактически заставляет сервер просматривать все данные для всех предыдущих страниц. При выполнении запроса каждая страница загружается все дольше и дольше, и я могу сказать, что это превращается в квадратичную операцию. Эта проблема появилась в следующих постах:

LINQ Skip() Problem LINQ2SQL select orders and skip/take

Кажется, я не могу найти способ сделать это с помощью LINQ, который позволяет мне ограниченно использовать память при подкачке данных, и в то же время загружать каждую страницу в постоянном времени. Есть ли способ сделать это правильно?My hunch is that there might be some way to tell the DataContext to explicitly forget about the object in the first approach above, but I can't find out how to do that.

Ответы на вопрос(1)

Ваш ответ на вопрос