2017-02-12 77 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$ 

对于后代也有类似的方法。