2013-06-04 3 views
1

Этот запрос был написан в нашей системе некоторое время назад, но производительность этого запроса ухудшается при небольшом увеличении объема данных. В моем исследовании показано (CodeCount), где запрос запускает другой подзапрос, вызывающий значительную задержку в выполнении. Мне нужно оптимизировать этот запрос Linq. любая помощь будет высоко оцененSubQuery и Group by in linq

from batch in Context.VoucherCodeBatch.ToList() 
        join type in Context.VoucherCodeType on batch.VoucherTypeId equals type.VoucherTypeId 
        join voucher in Context.Voucher on batch.VoucherCodeBatchId equals voucher.VoucherCodeBatchId 

        where batchIds.Contains(batch.BatchCode) 
        group new 
        { 
         batch.BatchCode, 
         batch.CreationDate, 
         type.VoucherTypeName, 
         voucher.AllowedCount, 
         voucher.ValidFrom, 
         voucher.ValidTo, 
         batch.VoucherCodeBatchId, 
         voucher.VoucherCode 
        } 
         by new { batch.BatchCode } 
         into uniquebatch 
         select new Batch 
         { 
          BatchCode = uniquebatch.FirstOrDefault().BatchCode, 
          CreationDate = uniquebatch.FirstOrDefault().CreationDate, 
          TimesAllowed = uniquebatch.FirstOrDefault().AllowedCount, 
          ValidFrom = uniquebatch.FirstOrDefault().ValidFrom, 
          CodeCount = ((from c in Context.Voucher.ToList() 
              where 
               c.VoucherCodeBatchId == 
               uniquebatch.FirstOrDefault().VoucherCodeBatchId 
              select c).Count()), 
          ValidTo = uniquebatch.FirstOrDefault().ValidTo, 
          CodeType = uniquebatch.FirstOrDefault().VoucherTypeName, 
          VoucherCodeBatchId = uniquebatch.FirstOrDefault().VoucherCodeBatchId 
         }); 
+3

Этот 'ToList()' там означает, что этот запрос запрашивает * все * Строки ваучера из базы данных и фильтрует в памяти. Попробуйте удалить его. –

+0

Я бы рекомендовал делать такие запросы в SQL на стороне БД. –

+0

Я согласен с Эвальдом. Возможно, даже превратив его в представление, которое вы можете выбрать в LINQ намного проще. Много раз, только потому, что вы можете сделать это в LINQ, это не значит, что это лучший способ сделать это. –

ответ

1

Первый большой проблемой является ToList() прямо в передней части ObjectSet <> (коллекция таблицы в EF).

Никогда не делайте этого, чтобы заставить EF доставлять все данные в память, прежде чем обрабатывать запрос. (Как @ Даниэль Хильгарт).

Другая деталь использовать свойство получить перед FirstOrDefault() как в строке:

BatchCode = uniquebatch.FirstOrDefault().BatchCode, 

Использование First() вместо FirstOrDefault в этом случае. как:

BatchCode = uniquebatch.First().BatchCode, 

Ваш запрос будет выглядеть следующим образом:

from batch in Context.VoucherCodeBatch/*.ToList()*/ 
join type in Context.VoucherCodeType on batch.VoucherTypeId equals type.VoucherTypeId 
join voucher in Context.Voucher on batch.VoucherCodeBatchId equals voucher.VoucherCodeBatchId 
where batchIds.Contains(batch.BatchCode) 
group new 
    { 
     batch.BatchCode, 
     batch.CreationDate, 
     type.VoucherTypeName, 
     voucher.AllowedCount, 
     voucher.ValidFrom, 
     voucher.ValidTo, 
     batch.VoucherCodeBatchId, 
     voucher.VoucherCode 
    } 
by new { batch.BatchCode } 
into uniquebatch 
select (delegate 
    { 
     // If you put a operation in a query that operation will be 
     // processed all times. Bacause that i removed this line from 
     // the where statement. 
     var vcBatchId = uniquebatch.First().VoucherCodeBatchId; 

     return new Batch 
      { 
       BatchCode = uniquebatch.First().BatchCode, 
       CreationDate = uniquebatch.First().CreationDate, 
       TimesAllowed = uniquebatch.First().AllowedCount, 
       ValidFrom = uniquebatch.First().ValidFrom, 
       CodeCount = ((
        from c in Context.Voucher/*.ToList()*/ 
        where c.VoucherCodeBatchId == vcBatchId 
        select c).Count()), 
       ValidTo = uniquebatch.First().ValidTo, 
       CodeType = uniquebatch.First().VoucherTypeName, 
       VoucherCodeBatchId = uniquebatch.First().VoucherCodeBatchId 
      } 
    }); 

Если это улучшение не будет достаточно хорошо, Вам нужно будет изменить этот запрос к SQL. Но я считаю, что это улучшение будет намного лучше.

+0

Спасибо, что посмотрели на это. Что означает делегат. Я точно скопировал вышеуказанный код, и компилятор жалуется на select (delegate). Тип выражения в предложении select неверен. Ошибка ввода типа в вызове «Выбрать» » – user1071222