0

使用下表定义:

CREATE TABLE Nodes(id INTEGER, child INTEGER);

INSERT INTO Nodes(id, child) VALUES(1, 10);
INSERT INTO Nodes(id, child) VALUES(1, 11);
INSERT INTO Nodes(id, child) VALUES(1, 12);

INSERT INTO Nodes(id, child) VALUES(10, 100);
INSERT INTO Nodes(id, child) VALUES(10, 101);
INSERT INTO Nodes(id, child) VALUES(10, 102);

INSERT INTO Nodes(id, child) VALUES(2, 20);
INSERT INTO Nodes(id, child) VALUES(2, 21);
INSERT INTO Nodes(id, child) VALUES(2, 22);

INSERT INTO Nodes(id, child) VALUES(20, 200);
INSERT INTO Nodes(id, child) VALUES(20, 201);
INSERT INTO Nodes(id, child) VALUES(20, 202);

使用以下查询:

WITH RECURSIVE members(base, id, level) AS ( 
    SELECT n1.id, n1.id, 0
    FROM Nodes n1
    LEFT OUTER JOIN Nodes n2 ON n2.child = n1.id
    WHERE n2.id IS NULL

    UNION 

    SELECT m.base, n.child, m.level + 1
    FROM members m 
    INNER JOIN Nodes n ON  m.id=n.id
) 
SELECT m.id, m.level 
FROM members m 
WHERE m.base IN (1)

是否在递归 CTE 中优化了外部 WHERE 子句?我考虑使用的替代方法是:

WITH RECURSIVE members(id, level) AS ( 
    VALUES (1, 0)

    UNION 

    SELECT n.child, m.level + 1
    FROM members m 
    INNER JOIN Nodes n ON  m.id=n.id
) 
SELECT m.id, m.level 
FROM members m 

但它的问题是无法从中创建视图。因此,如果两者之间的性能差异很小,我更愿意从递归 CTE 创建一个视图,然后只查询它。

4

2 回答 2

1

为了能够将 WHERE 子句应用于 CTE 中的查询,数据库需要证明

  • 第一列中的所有值都不会被递归更改并返回基本查询,并且通常,
  • 任何过滤掉的行都不可能有任何可能出现在查询结果中的子代,或以任何其他方式影响 CTE。

这样的证明者是不存在的。见Subquery flattening的限制 22 。

于 2014-09-28T08:11:25.367 回答
0

要了解为什么您的第一个查询不是最优的,请尝试使用 UNION ALL 而不是仅使用 UNION 来运行这两个查询。给定样本数据后,第一个将返回 21 行,而第二个仅返回 7 行。

随后通过执行排序和重复消除来消除实际第一个查询中的重复行,而实际第二个查询中不需要此步骤。

于 2014-09-28T05:05:58.717 回答