2013-06-04 3 views
1

이 쿼리는 이전에 우리 시스템에 작성되었지만이 쿼리의 성능은 약간의 데이터 증가로 인해 좋지 않습니다. 내 조사 결과 (CodeCount) 쿼리에서 다른 하위 쿼리가 발생하여 실행이 많이 지연되었습니다. 이 Linq 쿼리를 최적화해야합니다. 어떤 도움은 매우 첫 번째 큰 문제를 잘 ObjectSet <의 앞에 ToList()> (EF의 테이블 컬렉션)이다linq의 SubQuery 및 Group

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

나는 DB 측에서 SQL 같은 쿼리를하는 것이 좋습니다. –

+0

나는 Ewald에 동의합니다. 어쩌면 LINQ에서 훨씬 쉽게 선택할 수있는보기로 만들 수도 있습니다. 많은 시간, LINQ에서 할 수 있다고해서 그것이 최선의 방법이라는 것을 의미하지는 않습니다. –

답변

1

을 이해할 수있을 것이다.

절대 수행하지 마십시오. ToList() EF가 모든 데이터를 메모리로 가져 와서 쿼리를 처리합니다. (@Daniel Hilgarth 주석처럼).

BatchCode = uniquebatch.FirstOrDefault().BatchCode, 

사용 First() 대신 FirstOrDefault을이 경우 :

기타 세부 사항 행에 같은 FirstOrDefault() 앞에 GET 속성을 사용합니다. 같은 :

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 절에있는 식의 형식이 잘못되었습니다. 'Select'에 대한 호출에서 형식 유추가 실패했습니다." – user1071222