2013-06-25 9 views
1

바깥 쪽 적용보기를 사용할 때 이상한 쿼리 속도 결과가 나타납니다.보기에서 2 개의 다른 열에 고유 카운트를 수행하고 있습니다. 1 회는 0.1 초 이내에 완료되고, 다른 하나는 0.1 초 이내에 수행됩니다. 4-6 초가 걸리며 두 번째 카운트 쿼리가 바깥 쪽 적용의 일부이기 때문에 느리게 반환됩니까? 그렇다면 어떻게이 쿼리를 빠르게 할 수 있습니까?SQL보기 바깥 쪽 적용 속도

빠른 고유 한 카운트입니다 -

SELECT DISTINCT ISNULL([ItemType], 'N/A') AS Items FROM vwCustomerItemDetailsFull 

느린 고유 한 카운트입니다 -

SELECT DISTINCT ISNULL([CustomerName], 'N/A') AS Items FROM vwCustomerItemDetailsFull 

뷰는 -

SELECT I.ItemID, 
     IT.Name AS ItemType, 
     CASE 
     WHEN CustomerItemEndDate IS NULL 
       OR CustomerItemEndDate > GETDATE() THEN CustomerItems.CustomerName 
     ELSE NULL 
     END  AS CustomerName, 
     CASE 
     WHEN CustomerItemEndDate IS NULL 
       OR CustomerItemEndDate > GETDATE() THEN CustomerItems.CustomerNumber 
     ELSE NULL 
     END  AS CustomerNumber, 
     CASE 
     WHEN CustomerItemEndDate IS NULL 
       OR CustomerItemEndDate > GETDATE() THEN CustomerItems.CustomerItemStartDate 
     ELSE NULL 
     END  AS CustomerItemStartDate, 
FROM tblItems I 
     INNER JOIN tblItemTypes IT 
     ON I.ItemTypeID = IT.ItemTypeID 
     OUTER APPLY (SELECT TOP 1 CustomerName, 
           CustomerNumber, 
           StartDate AS CustomerItemStartDate, 
           EndDate AS CustomerItemEndDate 
        FROM tblCustomerItems CI 
          INNER JOIN tblCustomers C 
          ON C.CustomerID = CI.CustomerID 
        WHERE CI.ItemID = I.ItemID 
        ORDER BY EndDate DESC) AS CustomerItems 
+2

'OUTER APPLY'는 결과에 영향을 미치지 않으므로 'ItemType'대소 문자는 절대 실행되지 않습니다. 실행 계획은 어떻게 생겼습니까? –

답변

3

실행 계획을 확인,이 속도의 차이는 이상하지 않습니다. 외부 적용이고 십자가 적용이 아니기 때문에, 그 안에는 결과를 제한하고 있습니다. o top 1은 외부 적용이 쿼리 결과 수 또는 ItemType 열에 영향을 미치지 않는다는 것을 의미합니다.

따라서보기에서 선택하고 외부 적용의 열을 사용하지 않으면 옵티마이 저는 실행이 필요하지 않음을 알만큼 충분히 똑똑합니다. 따라서 첫 번째 쿼리는 다음과 같습니다.

SELECT DISTINCT ISNULL([ItemType], 'N/A') AS Items 
FROM ( SELECT tblItems 
      FROM Items 
        INNER JOIN tblItemTypes IT 
         ON I.ItemTypeID = IT.ItemTypeID 
     ) vw 

반면에 두 번째 쿼리는 외부 적용을 실행해야합니다.

이전에 유용하다고 생각되는 longer answer을 게시했습니다.

SELECT I.ItemID, 
     IT.Name AS ItemType, 
     CustomerName, 
     CustomerNumber, 
     CustomerItemStartDate, 
FROM tblItems I 
     INNER JOIN tblItemTypes IT 
      ON I.ItemTypeID = IT.ItemTypeID 
     LEFT JOIN 
     ( SELECT ci.ItemID, 
        CustomerName, 
        CustomerNumber, 
        StartDate AS CustomerItemStartDate, 
        EndDate AS CustomerItemEndDate, 
        RN = ROW_NUMBER() OVER (PARTITION BY ci.ItemID ORDER BY EndDate DESC) 
      FROM tblCustomerItems CI 
        INNER JOIN tblCustomers C 
         ON C.CustomerID = CI.CustomerID 
     ) AS CustomerItems 
      ON CustomerItems.ItemID = I.ItemID 
      AND CustomerItems.rn = 1 
      AND CustomerItems.CustomerItemEndDate < GETDATE(); 

그러나 나는 당신이 말했다 때문에이 정도 성능이 향상됩니다 생각하지 않는다 : 당신은 너무로 다시 작성할 수 있습니다 가입에 쿼리를 변경하고자한다면

편집

가장 값 비싼 부분은 EndDate에있는 정렬이고, 첫 번째 쿼리의 경우 옵티마이 저가 더 이상 외부 적용을 최적화하지 않기 때문에 성능에 부정적인 영향을 미칩니다.

데이터 크기 또는 분포를 알지 못하고 인덱스를 추가하는 것이 성능 향상에 가장 좋은 방법이라고 생각합니다. 실제 실행 계획을 보여주는 자체 쿼리를 실행하면 정확한 인덱스를 정확히 추측 할 수 없습니다. SSMS는 내 최고의 추측보다 나은 색인을 제안합니다.

+0

더 느린 선택에 대한 실행 계획에 따르면 - 외부 적용의 정렬이 쿼리 시간의 96 %를 유발하는 것 같습니다. – user1948635

+0

더 빠른 경우에는 외부 적용이 전혀 나타나지 않습니까? – GarethD

+0

올바른 경우 외부 적용이 적용되지 않으며 실행 계획이 훨씬 간단합니다. – user1948635