ツリー構造で再帰CTEを使用して、ツリー内の特定のノードのすべての子孫をリストしています。WHERE
句にリテラルノード値を書き込むと、SQL Serverは実際にその値にのみCTEを適用し、実際の行数が少ないクエリプランなどを提供します。
ただし、値をパラメーターとして渡すと、CTEが実現(スプール)され、事実の後でフィルター処理されるようです。
私は計画を間違って読んでいた可能性があります。パフォーマンスの問題には気づきませんでしたが、CTEの実現により、特にビジーなシステムでは、より大きなデータセットで問題が発生する可能性があると心配しています。また、私は通常、このトラバーサルをそれ自体で複合します。祖先までトラバースし、子孫まで戻ります(すべての関連ノードを確実に収集するため)。私のデータが原因で、「関連」ノードの各セットはかなり小さいため、CTEの実現は意味がありません。また、SQL ServerがCTEを実現しているように見える場合、その「実際の」数には非常に多くの数値が含まれています。
クエリのパラメーター化されたバージョンをリテラルバージョンのように機能させる方法はありますか?CTEを再利用可能なビューにしたいと考えています。
リテラルを使用したクエリ:
CREATE PROCEDURE #c AS BEGIN;
WITH descendants AS (SELECT
t.ParentId Id
,t.Id DescendantId
FROM #tree t
WHERE t.ParentId IS NOT NULL
UNION ALL SELECT
d.Id
,t.Id DescendantId
FROM descendants d
JOIN #tree t ON d.DescendantId = t.ParentId)
SELECT d.*
FROM descendants d
WHERE d.Id = 24
ORDER BY d.Id, d.DescendantId;
END;
GO
EXEC #c;
パラメータ付きのクエリ:
CREATE PROCEDURE #c (@Id BIGINT) AS BEGIN;
WITH descendants AS (SELECT
t.ParentId Id
,t.Id DescendantId
FROM #tree t
WHERE t.ParentId IS NOT NULL
UNION ALL SELECT
d.Id
,t.Id DescendantId
FROM descendants d
JOIN #tree t ON d.DescendantId = t.ParentId)
SELECT d.*
FROM descendants d
WHERE d.Id = @Id
ORDER BY d.Id, d.DescendantId;
END;
GO
EXEC #c 24;
セットアップコード:
DECLARE @count BIGINT = 100000;
CREATE TABLE #tree (
Id BIGINT NOT NULL PRIMARY KEY
,ParentId BIGINT
);
CREATE INDEX tree_23lk4j23lk4j ON #tree (ParentId);
WITH number AS (SELECT
CAST(1 AS BIGINT) Value
UNION ALL SELECT
n.Value * 2 + 1
FROM number n
WHERE n.Value * 2 + 1 <= @count
UNION ALL SELECT
n.Value * 2
FROM number n
WHERE n.Value * 2 <= @count)
INSERT #tree (Id, ParentId)
SELECT n.Value, CASE WHEN n.Value % 3 = 0 THEN n.Value / 4 END
FROM number n;