2017-02-12 68 views
1

我有一張表表示層次結構鏈接圖(parent_id,child_id) 該表具有父,子和兩者的索引。 該圖可能包含循環,我需要檢查它們(或者,也許我需要找到所有循環來消除它們)。postgresql忽略遞歸查詢的索引

而我需要查詢一個節點的所有父母recustively。 爲此,我使用此查詢(它應該考慮到保存):

WITH RECURSIVE recursion(parent_id, child_id, node_id, path) AS (
    SELECT h.parent_id, 
     h.child_id, 
     h.child_id AS node_id, 
     ARRAY[h.parent_id, h.child_id] AS path 
     FROM hierarchy h 
    UNION ALL 
    SELECT h.parent_id, 
     h.child_id, 
     r.node_id, 
     ARRAY[h.parent_id] || r.path 
     FROM hierarchy h JOIN recursion r ON h.child_id = r.parent_id 
     WHERE NOT r.path @> ARRAY[h.parent_id] 
    ) 
SELECT parent_id, 
    child_id, 
    node_id, 
    path 
    FROM recursion 
    where node_id = 883 

對於此查詢的Postgres將使用非常了不起的計劃:

"CTE Scan on recursion (cost=2703799682.88..4162807558.70 rows=324223972 width=56)" 
" Filter: (node_id = 883)" 
" CTE recursion" 
" -> Recursive Union (cost=0.00..2703799682.88 rows=64844794481 width=56)" 
"   -> Seq Scan on hierarchy h (cost=0.00..74728.61 rows=4210061 width=56)" 
"   -> Merge Join (cost=10058756.99..140682906.47 rows=6484058442 width=56)" 
"    Merge Cond: (h_1.child_id = r.parent_id)" 
"    Join Filter: (NOT (r.path @> ARRAY[h_1.parent_id]))" 
"    -> Index Scan using hierarchy_idx_child on hierarchy h_1 (cost=0.43..256998.25 rows=4210061 width=16)" 
"    -> Materialize (cost=10058756.56..10269259.61 rows=42100610 width=48)" 
"      -> Sort (cost=10058756.56..10164008.08 rows=42100610 width=48)" 
"       Sort Key: r.parent_id" 
"       -> WorkTable Scan on recursion r (cost=0.00..842012.20 rows=42100610 width=48)" 

好像Postgres沒有理解node_id上​​的外部過濾器應用於第一個遞歸子查詢中的child_id。

我想我做錯了很多事情。但究竟在哪裏?

+1

通常情況下,在UNION的第一部分的條件:要麼頂級節點(沒有父)或葉節點(沒有孩子),或某些特定記錄#你有興趣在您的代碼使用。 *每個*記錄作爲連鎖起動器。 – wildplasser

+0

聯合的第一個查詢檢索表的所有**行。沒有指標將有助於與 –

+0

我希望能Postgres的內部子查詢合併外部過濾器。看起來我太樂觀了。 – qMax

回答

1

看起來像你只需要移動WHERE node_id = 883工會的第一部分:

WITH RECURSIVE recursion(parent_id, child_id, node_id, path) AS (
    SELECT h.parent_id, 
     h.child_id, 
     h.child_id AS node_id, 
     ARRAY[h.parent_id, h.child_id] AS path 
     FROM hierarchy h 
     WHERE node_id = 883 
    UNION ALL 
    SELECT h.parent_id, 
     h.child_id, 
     r.node_id, 
     ARRAY[h.parent_id] || r.path 
     FROM hierarchy h JOIN recursion r ON h.child_id = r.parent_id 
     WHERE NOT r.path @> ARRAY[h.parent_id] 
    ) 
SELECT parent_id, 
    child_id, 
    node_id, 
    path 
    FROM recursion 
+0

在這種情況下我不能保存查詢到視圖,但僅與作爲起始濾波器輸入參數的函數。 – qMax

+1

函數是參數化的視圖:-)。只有使用非遞歸部分的地方,你才能加快查詢速度。 –

+0

是的。該功能可能確實是我需要的。 – qMax

0

這是更有效的方式來解決遍歷任務的圖。

CREATE OR REPLACE FUNCTION public.terr_ancestors(IN bigint) 
RETURNS TABLE(node_id bigint, depth integer, path bigint[]) AS 
$BODY$ 
WITH RECURSIVE recursion(node_id, depth, path) AS (
    SELECT $1 as node_id, 0, ARRAY[$1] AS path 
    UNION ALL 
    SELECT h.parent_id as node_id, r.depth + 1, h.parent_id || r.path 
    FROM hierarchy h JOIN recursion r ON h.child_id = r.node_id 
    WHERE h.parent_id != ANY(path) 
) 
SELECT * FROM recursion 
$BODY$ 

對於後代也有類似的方法。