2012-04-18 16 views
1

UNIONを含むクエリからページングされたデータを返すSPがあります。これは私のDBを殺していると時々実行するために30秒かかる、私はここに何かを見逃している?パフォーマンスを改善するために私は何ができますか?関与SELECT UNIONでページングを超過し、サーバーを強制終了する

テーブル:製品、カテゴリー、CategoryProducts

目標: カテゴリーに含まれていないか、Webサービスのためのそれらの上のカテゴリやページ内のすべての製品現在のカテゴリ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

私があなたの状況を正しく読んだ場合、2つの異なるクエリを持つ唯一の理由は、見つからない/削除されたCategoryProductsの扱いです。私はIsDeleted = 0と左の結合でこの問題を解決しようとしましたが、削除されたCategoryProductsをすべてnullにするため、再度テストする必要はありません。 ModifiedOnパーツは、検索したいCategoryproductsが見つからない/削除されたためのnullの別のテストがあります。私はそのカテゴリがCategoryProductsにフィルタなどを除いて、すべてで使用されて表示されていない第三の外観に

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 

。この場合、2番目のLEFT JOINをINNER JOINに変更し、このセクションをカッコ内に囲む必要があります。

関連する問題