postgresql 忽略递归查询的索引

标签 postgresql hierarchical-data recursive-query

我有一个表示层次结构链接图的表(parent_id,child_id) 该表在父项、子项和两者上都有索引。 该图可能包含循环,我需要检查它们(或者,也许我需要找到所有循环以消除它们)。

而且我需要递归地查询一个节点的所有父节点。 为此,我使用了这个查询(它应该保存在 View 中):

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。

我想我做错了。但具体在哪里?

最佳答案

看起来您只需要将 WHERE node_id = 883 移动到 union 的第一部分:

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

关于postgresql 忽略递归查询的索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42190676/

相关文章:

ruby - 哪个 Ruby ORM 支持 PostgreSQL 数组数据类型?

php - 可以在 PHP/MySQL 递归函数中使用 JOIN 吗?

sql - 计算路径数

python - 迁移时出错 - psycopg2 Django

mysql - 将 Biginteger 转换为 long 会导致错误

sql - 如何对包含子组的有序列表进行 SQL 查询?

elasticsearch - 如何在ElasticSearch中反规范化层次结构?

mysql - 如何从sql表中查找父子树

sql - 没有父/子关系的递归实体

java - 如何将在 JDBC 中执行的 SQL 查询的结果分配给 java 变量?