外部WHERE子句是否在递归CTE中进行了优化?

时间:2014-09-28 04:31:17

标签: sql sqlite recursive-cte

使用以下表定义:

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)

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

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创建一个视图,然后只是查询它。

2 个答案:

答案 0 :(得分:1)

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

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

这样的证明者不存在。 请参阅Subquery flattening的限制22。

答案 1 :(得分:0)

要了解您的第一个查询不是最佳查询的原因,请尝试使用UNION ALL而不是UNION运行它们。在给出样本数据的情况下,第一行将返回21行,而第二行仅返回7.

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