Tôi đang sử dụng CTE đệ quy trên cấu trúc cây để liệt kê tất cả các hậu duệ của một nút cụ thể trong cây. Nếu tôi viết một giá trị nút bằng chữ trong WHERE
mệnh đề của mình , SQL Server dường như thực sự áp dụng CTE chỉ cho giá trị đó, đưa ra một kế hoạch truy vấn với số lượng hàng thực tế thấp, et cetera :
Tuy nhiên, nếu tôi truyền giá trị dưới dạng tham số, có vẻ như nhận ra (spool) CTE và sau đó lọc nó sau khi thực tế :
Tôi có thể đọc sai kế hoạch. Tôi chưa nhận thấy vấn đề về hiệu năng, nhưng tôi lo lắng rằng việc thực hiện CTE có thể gây ra sự cố với các tập dữ liệu lớn hơn, đặc biệt là trong một hệ thống bận rộn hơn. Ngoài ra, tôi thường kết hợp điều này qua chính nó: Tôi đi ngược lại tổ tiên và quay trở lại con cháu (để đảm bảo rằng tôi thu thập tất cả các nút liên quan). Do dữ liệu của tôi như thế nào, mỗi tập hợp các nút có liên quan đến các mối quan hệ khác nhau khá nhỏ, do đó việc thực hiện CTE không có ý nghĩa gì. Và khi SQL Server dường như nhận ra CTE, nó sẽ cho tôi một số lượng khá lớn trong số đếm thực tế của nó.
Có cách nào để có được phiên bản tham số của truy vấn để hoạt động như phiên bản theo nghĩa đen không? Tôi muốn đặt CTE trong một cái nhìn có thể tái sử dụng.
Truy vấn bằng chữ:
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;
Truy vấn với tham số:
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;
Mã cài đặt:
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;