2013-03-06 2 views
3

Я пытаюсь получить каждую запись из таблицы в базе данных MS SQL с примерно 20 миллионами записей через модель данных сущности. Моя первоначальная идея состояла в том, чтобы получить данные в кусках, например, так:Обработка больших SQL-запросов с помощью LINQ

public IEnumerable<IEnumerable<device>> GetDevicesInChunks(int chunkSize) 
{ 
    using (var db = new AccountsEntities()) 
    { 
     for (int i = 0; i < db.devices.Count(); i += chunkSize) 
     { 
      yield return db.devices.Skip(i).Take(chunkSize); 
     } 
    } 
} 

Тем не менее, кажется, что я должен позвонить OrderBy, прежде чем я называю Skip, судя по тому исключению, что брошен, когда я использую вышеупомянутый метод

The method 'Skip' is only supported for sorted input in LINQ to Entities. The method 
'OrderBy' must be called before the method 'Skip'. 

Я уверен, что при вызове OrderBy на каждом подмножестве записей, которые я получаю, будет дорого, так как устройства не имеют особого порядка - я чувствую, что я иду по неправильному пути здесь.

Каков наилучший подход к обработке больших SQL-запросов через LINQ?

+0

Можете ли вы не использовать 'Where' и фильтровать первичный ключ вместо' Skip'? Или просто 'OrderBy' первичный ключ? –

+0

Есть ли какая-то особая причина, почему вы должны делать это в кусках? – Tory

+2

@Tory Я думаю, что загрузка 20 миллионов объектов сразу была бы достаточной причиной. –

ответ

2

Ошибка возникает из-за того, что метод Skip пропускается после OrderBy. Вы не можете запустить Пропуск без OrderBy. Метод Skip должен знать первый, который нужно принять, и если вы поместите то, что является первым, которому необходимо знать порядок выбора, чтобы узнать, является ли первое число с начала до конца или заканчивается до начала.

Вы можете прочитать больше here

Таким образом, ваш код выглядит следующим образом:

public IEnumerable<IEnumerable<device>> GetDevicesInChunks(int chunkSize) 
{ 
    using (var db = new AccountsEntities()) 
    { 
     for (int i = 0; i < db.devices.Count(); i += chunkSize) 
     { 
      yield return db.devices.OrderByDescending(y => y).Skip(i).Take(chunkSize); 
     } 
    } 
} 

, если вы считаете, что был тяжелый запрос, Remeber Entity Framework может сделать кэш запросов и данных , Если вам не нравится sql этого метода, вы можете run the query manually.

Персональный эксперимент: Я использую это с базой данных с двумя би строками и ... это не было медленным. Но у меня есть индекс в моей таблице, и я всегда использую кеш.

Для получения дополнительной информации: Вы можете использовать процедуры, если хотите. Подробнее here

+0

Очень полный ответ, спасибо за всю информацию и объяснение! Чтобы убедиться, что я правильно понимаю, выражение OrderByDescending должно быть y => y.id not y => y, right? –

+0

ops, может быть, это может быть – MayogaX

0

Вы можете не делать OrderBy - просто, возможно, потребуется, чтобы заполнить список, прежде чем делать Skip и Take. Я думаю, вы можете использовать .Count() для заполнения запроса, после чего вы можете использовать Skip и Take.

+0

Это будет очень тяжело, используя Count или ToList, как вы сказали, заполнит запрос, но получит 20 миллионов записей. –

+0

True ... но он не будет выталкивать весь набор из сервера только для того, чтобы сделать счет - он заполнит его в MSSQL. –

Смежные вопросы