Saya menggunakan CTE rekursif pada struktur pohon untuk mendaftar semua keturunan dari simpul tertentu di pohon. Jika saya menulis nilai simpul literal dalam WHERE
klausa saya , SQL Server tampaknya benar-benar menerapkan CTE hanya untuk nilai itu, memberikan rencana kueri dengan jumlah baris aktual yang rendah, dan lain-lain :
Namun, jika saya meneruskan nilai sebagai parameter, tampaknya menyadari (spool) CTE dan kemudian memfilternya setelah fakta :
Saya bisa salah membaca rencana. Saya belum melihat masalah kinerja, tetapi saya khawatir bahwa realisasi CTE dapat menyebabkan masalah dengan kumpulan data yang lebih besar, terutama dalam sistem yang lebih sibuk. Juga, saya biasanya memperumit lintasan ini pada dirinya sendiri: Saya melintasi leluhur dan kembali ke keturunan (untuk memastikan bahwa saya mengumpulkan semua simpul terkait). Karena bagaimana data saya, setiap set node "terkait" agak kecil, sehingga realisasi CTE tidak masuk akal. Dan ketika SQL Server tampaknya menyadari CTE, itu memberi saya beberapa angka yang cukup besar dalam jumlah "aktual".
Apakah ada cara untuk mendapatkan versi kueri parameter untuk bertindak seperti versi literal? Saya ingin menempatkan CTE dalam tampilan yang dapat digunakan kembali.
Pertanyaan dengan literal:
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;
Kueri dengan parameter:
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;
Kode pengaturan:
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;