PostgreSQL具有RECURSIVE性能

jul*_*icz 14 database postgresql recursive-query with-statement

我有一个简单的问题.不知怎的,我无法找到明确的答案.

有多少是WITH RECURSIVE语法PostgreSQL的优化?我的意思是:它仅仅是一系列非递归查询的语法糖,或者它是一个单一的语句,尽管其复杂的语义已经作为一个整体进行了优化.一个后续问题 - 关于优化这种语法的可能性有多大?当然,非常欢迎有关此事的一些具体数据.

Den*_*rdy 19

我发现它已经优化到一定程度.

各种子查询按预期重复使用并单独优化,Postgres就像任何其他查询一样优化后者.

我对它的主要抱怨是它不会在可能的情况下向CTE注入限制.

例如:

with recursive
parents as (
select node.id,
       node.parent_id
from nodes as node
union all
select node.id,
       parent.parent_id
from parents as node
join nodes as parent on parent.id = node.parent_id
)
select parent_id
from parents
where id = 2;
Run Code Online (Sandbox Code Playgroud)

Postgres的理想地理解,在上面的,是(因为node.id返回原样),它可以这样做:

with recursive
parents as (
select node.id,
       node.parent_id
from nodes as node
where id = 2
union all
select node.id,
       parent.parent_id
from parents as node
join nodes as parent on parent.id = node.parent_id
)
select parent_id
from parents;
Run Code Online (Sandbox Code Playgroud)

...并在主键上使用索引扫描.在实践中,它实际上确实在CTE告诉它做的时候:递归地拉出所有行的所有父项,如果需要,将结果集放在一个未命名的临时表中,然后检查结果集中的每一行为id = 2.

换句话说,CTE不会跟踪它返回的"原始"表/行/列集.在正确优化之前,在递归查询上创建视图充其量是疯狂的.

同时一个好的解决方法是创建一个sql函数:

create function parents(id int) as returns table (id int) $$
    with recursive
    parents as (
    select node.id,
           node.parent_id
    from nodes as node
    where id = $1
    union all
    select node.id,
           parent.parent_id
    from parents as node
    join nodes as parent on parent.id = node.parent_id
    )
    select parent_id
    from parents;
$$ language sql stable strict rows 5 cost 1;
Run Code Online (Sandbox Code Playgroud)

另一个问题是你不能使用FOR UPDATE和递归CTE(事实上,出于同样的原因).


小智 6

我的经验是,它确实优化得很好。

检查由 EXPLAIN ANALYZE 生成的查询的执行计划您将看到它到底有多么“昂贵”(然后将其与自编写的递归函数进行比较)

  • 在语言级别使用“WITH RECURSIVE”的全部原因是数据库知道您要做什么,然后可以根据您的意图采取行动。 (2认同)