2012-04-18 2 views
1

UNION이 포함 된 쿼리에서 페이징 된 데이터를 반환하는 SP가 있습니다. 이건 내 DB를 죽이고 때로는 실행 30 초 데, 내가 여기 뭔가 명백한 누락 된 건가요? 성능 향상을 위해 무엇을 할 수 있습니까? 참여SELECT UNION에서 페이징 오버 저속 및 내 서버 죽이기

테이블 : 제품, 카테고리, CategoryProducts

목표 : 카테고리에없는 또는 웹 서비스에 대한 그들에 카테고리 페이지에있는 모든 제품 현재 카테고리 UNION에서 삭제 된 모든 제품.

내가 가입중인 모든 열에 인덱스가 있고 데이터베이스에 427,996 개의 제품, 6148 개의 카테고리 및 409,691 개의 카테고리 제품이 있습니다.

다음은 6 사이에 걸리는 내 쿼리이며, 30 초 실행 :

SELECT * FROM (
    SELECT ROW_NUMBER() OVER(ORDER BY Products.ItemID, Products.ManufacturerID) AS RowNum, * 
     FROM 
     (
     SELECT Products.*, 
       CategoryID = NULL, CategoryName = NULL, 
       CategoryProductID = NULL, 
          ContainerMinimumQuantity = 
          CASE COALESCE(Products.ContainerMinQty, 0) 
           WHEN 0 THEN Products.OrderMinimumQuantity 
           ELSE Products.ContainerMinQty 
          END 
          Products.IsDeleted, 
          SortOrder = NULL 
    FROM CategoryProducts RIGHT OUTER JOIN Products 
     ON CategoryProducts.ManufacturerID = Products.ManufacturerID 
      AND CategoryProducts.ItemID = Products.ItemID 
      WHERE  (Products.ManufacturerID = @ManufacturerID) 
       AND (Products.ModifiedOn > @tStamp) 
       AND ((CategoryProducts.IsDeleted = 1) OR (CategoryProducts.IsDeleted IS NULL)) 

       UNION 

       SELECT Products.*, 
CategoryProducts.CategoryID , CategoryProducts.CategoryName, 
      CategoryProducts.CategoryProductID , 
          ContainerMinimumQuantity = 
          CASE COALESCE(Products.ContainerMinQty, 0) 
           WHEN 0 THEN Products.OrderMinimumQuantity 
           ELSE Products.ContainerMinQty 
          END 
          CategoryProducts.IsDeleted, 
          CategoryProducts.SortOrder 
    FROM  Categories INNER JOIN 
          CategoryProducts ON Categories.CategoryID = CategoryProducts.CategoryID INNER JOIN 
          Products ON CategoryProducts.ManufacturerID = Products.ManufacturerID 
      AND CategoryProducts.ItemID = Products.ItemID 
    WHERE  (Products.ManufacturerID = @ManufacturerID) 
      AND (Products.ModifiedOn > @tStamp OR CategoryProducts.ModifiedOn > @tStamp)) 
      AS Products) AS C 
     WHERE RowNum >= @StartRow AND RowNum <= @EndRow 

어떤 통찰력을 크게 감상 할 수있다.

+1

쿼리를 살펴보기 전에 실행 계획의 모양을 알려주시겠습니까? (대량, 즉 인덱스 스캔을하고 있습니까?) – McGarnagle

+1

노동 조합이 필요합니까, 아니면 모든 노동 조합이됩니까? –

+0

@TimLehner 필자는 그것이 내게 영향을 미칠 것이라고 생각하지 않습니다. 성능에 큰 영향을 미칩니 까? – Slee

답변

0

귀하의 상황을 정확하게 읽으면, 두 개의 다른 쿼리가있는 유일한 이유는 빠진/삭제 된 CategoryProducts의 치료입니다. 나는이 문제를 왼쪽으로 IsDeleted = 0으로 합류하여 모든 삭제 된 CategoryProducts를 null로 가져 오려고 했으므로 다시 테스트 할 필요가 없습니다. ModifiedOn 부분은 누락/삭제 된 Categoryproducts에 대한 null에 대한 또 다른 테스트가 있습니다.

select * 
from (
    SELECT 
     Products.*, 
     -- Following three columns will be null for deleted/missing categories 
     CategoryProducts.CategoryID, 
     CategoryProducts.CategoryName, 
     CategoryProducts.CategoryProductID , 
     ContainerMinimumQuantity = COALESCE(nullif(Products.ContainerMinQty, 0), 
              Products.OrderMinimumQuantity), 
     CategoryProducts.IsDeleted, 
     CategoryProducts.SortOrder, 
     ROW_NUMBER() OVER(ORDER BY Products.ItemID, 
           Products.ManufacturerID) AS RowNum 
    FROM Products 
     LEFT JOIN CategoryProducts 
     ON CategoryProducts.ManufacturerID = Products.ManufacturerID 
     AND CategoryProducts.ItemID = Products.ItemID 
    -- Filter IsDeleted in join so we get nulls for deleted categories 
    -- And treat them the same as missing ones 
     AND CategoryProducts.IsDeleted = 0 
     LEFT JOIN Categories 
     ON Categories.CategoryID = CategoryProducts.CategoryID 
    WHERE Products.ManufacturerID = @ManufacturerID 
     AND (Products.ModifiedOn > @tStamp 
     -- Deleted/missing categories 
      OR CategoryProducts.ModifiedOn is null 
      OR CategoryProducts.ModifiedOn > @tStamp) 
    ) C 
WHERE RowNum >= @StartRow AND RowNum <= @EndRow 

세 번째로 보면 카테고리가 CategoryProducts에 대한 필터를 제외하고 전혀 사용되지 않습니다. 이 경우 두 번째 LEFT JOIN이 INNER JOIN으로 변경되어야하며이 섹션은 괄호로 묶어야합니다.