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)

外部の 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 

しかし、そこからビューを作成できないという問題があります。したがって、2 つのパフォーマンスの違いが最小限である場合は、再帰 CTE からビューを作成し、それに対してクエリを実行することをお勧めします。

4

2 に答える 2

1

CTE 内のクエリに WHERE 句を適用できるようにするには、データベースがそれを証明する必要があります。

  • 最初の列のすべての値は再帰によって変更されず、基本クエリに戻ります。一般に、
  • 除外された行が、クエリの結果に表示される可能性のある子を持つことはできません。また、他の方法で CTE に影響を与えることもできません。

そのような証明者は存在しません。Subquery flatteningの制限 22 を参照してください。

于 2014-09-28T08:11:25.367 に答える
0

最初のクエリが最適ではない理由を確認するには、UNION だけでなく、UNION ALL を使用して両方を実行してみてください。与えられたサンプル データでは、最初の行は 21 行を返しますが、2 番目の行は 7 行しか返しません。

実際の最初のクエリの重複行は、並べ替えと重複排除を実行することによって削除されますが、この手順は実際の 2 番目のクエリでは必要ありません。

于 2014-09-28T05:05:58.717 に答える