6

サンプルデータの表は次のとおりです。

DECLARE @TestTable TABLE (
    ItemID INT,
    A INT,
    B INT,
    Month INT)

INSERT INTO @TestTable VALUES (1234, 5, 9, 1)
INSERT INTO @TestTable VALUES (1234, 6, 9, 2)
INSERT INTO @TestTable VALUES (4321, 5, 11, 1)
INSERT INTO @TestTable VALUES (4321, 12, 11, 2)
INSERT INTO @TestTable VALUES (1324, 14, 6, 1)
INSERT INTO @TestTable VALUES (1324, 5, 6, 2)
INSERT INTO @TestTable VALUES (1234, 1, 9, 3)
INSERT INTO @TestTable VALUES (1324, 9, 6, 3)

注意すべき点は、B列は、この計算で1回だけ使用されるのと常に同じですが、最初の計算に必要なことです。

最初の行でAからBを減算し、次に後続の行でAから前の行の差を減算しようとしています。事実上、最初の行で、次にB - A = C関連C - AするItemIDのすべての後続の行で。

これが私が期待している結果です:

ItemID  A   B   C   Month   RowNumber
1234    5   9   4   1       1
1234    6   9   -2  2       2
1234    1   9   -3  3       3
1324    14  6   -8  1       1
1324    5   6   -13 2       2
1324    9   6   -22 3       3
4321    5   11  6   1       1
4321    12  11  -6  2       2

これが私がこれを達成する方法です。

;WITH CTE_TestValue AS (
    SELECT 
        Main.ItemID,
        Main.A,
        Main.B,
        Main.Month,
        ROW_NUMBER() OVER (Partition BY Main.ItemID ORDER BY Main.Month) AS RowNumber
    FROM @TestTable AS Main
),
CTE_TestColumnC AS (
    SELECT 
        MainA.ItemID,
        MainA.A,
        MainA.B,
        (MainA.B - MainA.A) AS C,
        MainA.Month,
        MainA.RowNumber
    FROM CTE_TestValue AS MainA
        WHERE MainA.Rownumber = 1

    UNION ALL

    SELECT 
        MainB.ItemID,
        MainB.A,
        MainB.B,
        (Sub.C - MainB.A) AS C,
        MainB.Month,
        MainB.RowNumber
    FROM CTE_TestValue AS MainB
        INNER JOIN CTE_TestColumnC AS Sub
            ON MainB.RowNumber - 1 = Sub.RowNumber
            AND MainB.ItemID = Sub.ItemID
--      CROSS JOIN CTE_TestColumnC AS Sub
--          WHERE Sub.RowNumber + 1 = MainB.RowNumber
--          AND MainB.ItemID = Sub.ItemID 
)
SELECT 
    Main.ItemID,
    Main.A,
    Main.B,
    Main.C,
    Main.Month,
    Main.RowNumber
FROM CTE_TestColumnC AS Main
ORDER BY ItemID, Month, RowNumber

これは小さなデータサンプルでは問題なく機能しますが、私はそれぞれ約20,000個のItemIdを10回繰り返し処理しています。予想どおり、最初の行のすべての計算が即座に終了し、計算時間が大幅に増加します。

ご覧のとおり、私はとの両方を試しましINNER JOINCROSS JOIN。彼らは私が与えたパラメータで同じ実行計画を持っていると思いますCROSS JOIN

これを達成するためのより効果的/効率的な方法はありますか?

昨日これを5時間実行して、終了したかどうかを確認しました。終了しませんでした。

別の注意:これをテストデータで使用しているときは、うまくいけばスピードアップに役立てるためにSELECT使用していません。ORDERファクトチェックをしているときの便宜のORDERためです。

4

2 に答える 2

7

問題は、CTE を再帰 CTE のソースとして使用していることです。最初の CTE は、再帰 CTE の反復ごとに 1 回実行されます。テストデータでは、CTE_TestValue8回作成されたことを意味します。

CTE_TestValueクラスター化された主キーを持つ一時テーブルに結果を置き、その(RowNumber, ItemID)一時テーブルを再帰 CTE のデータ ソースとして使用しますCTE_TestColumnC

また、再帰部分の結合条件を に変更しON MainB.RowNumber = Sub.RowNumber + 1ます。これにより、クエリで一時テーブルのインデックスを使用できるようになります。

DECLARE @TestTable TABLE (
    ItemID INT,
    A INT,
    B INT,
    Month INT)

INSERT INTO @TestTable VALUES (1234, 5, 9, 1)
INSERT INTO @TestTable VALUES (1234, 6, 9, 2)
INSERT INTO @TestTable VALUES (4321, 5, 11, 1)
INSERT INTO @TestTable VALUES (4321, 12, 11, 2)
INSERT INTO @TestTable VALUES (1324, 14, 6, 1)
INSERT INTO @TestTable VALUES (1324, 5, 6, 2)
INSERT INTO @TestTable VALUES (1234, 1, 9, 3)
INSERT INTO @TestTable VALUES (1324, 9, 6, 3)

CREATE TABLE #TestValue
(
  ItemID INT,
  A INT,
  B INT,
  Month INT,
  RowNumber INT,
  primary key(RowNumber, ItemID)
)

INSERT INTO #TestValue
SELECT 
    Main.ItemID,
    Main.A,
    Main.B,
    Main.Month,
    ROW_NUMBER() OVER (Partition BY Main.ItemID ORDER BY Main.Month) AS RowNumber
FROM @TestTable AS Main


;WITH CTE_TestColumnC AS (
    SELECT 
        MainA.ItemID,
        MainA.A,
        MainA.B,
        (MainA.B - MainA.A) AS C,
        MainA.Month,
        MainA.RowNumber
    FROM #TestValue AS MainA
        WHERE MainA.Rownumber = 1

    UNION ALL

    SELECT 
        MainB.ItemID,
        MainB.A,
        MainB.B,
        (Sub.C - MainB.A) AS C,
        MainB.Month,
        MainB.RowNumber
    FROM #TestValue AS MainB
        INNER JOIN CTE_TestColumnC AS Sub
            ON MainB.RowNumber = Sub.RowNumber + 1
            AND MainB.ItemID = Sub.ItemID
)
SELECT 
    Main.ItemID,
    Main.A,
    Main.B,
    Main.C,
    Main.Month,
    Main.RowNumber
FROM CTE_TestColumnC AS Main
ORDER BY ItemID, Month, RowNumber

DROP TABLE #TestValue

クエリのクエリ プランでは、右下隅のテーブル スキャンに問題が示されています。このテスト データでは、8 回実行され、合計 64 行が返されます。

ここに画像の説明を入力

一時テーブルを使用したクエリのクエリ プラン: ここに画像の説明を入力 ここに画像の説明を入力

于 2012-10-11T06:17:18.227 に答える
0

あなたがやろうとしていることを正しく理解できたと思います。
これが私の解決策です:

WITH DATA AS (
SELECT *, row_number() over (ORDER BY itemid) RN
FROM TestTable),
RECURSIVE AS (
   SELECT itemID, B-A AS C, RN
  FROM DATA
  WHERE RN = 1
  UNION ALL
  SELECT T1.itemID, t2.C - t1.A, t1.RN
  FROM DATA AS T1
  INNER JOIN
  RECURSIVE AS T2
  ON t1.RN = T2.Rn+1)
SELECT ItemID, C
FROM RECURSIVE

完全な例(データを含む)はここにあります

于 2012-10-10T20:14:51.313 に答える