我有一个简单的问题。不知何故,我无法找到明确的答案。
WITH RECURSIVE
PostgreSQL中的语法优化了多少?我的意思是:它仅仅是一系列非递归查询的语法糖,还是它更像是一个语句,尽管其复杂的语义已经作为一个整体进行了优化。一个后续问题 - 优化这种语法有多少可能?当然,欢迎提供有关此事的具体数据。
我有一个简单的问题。不知何故,我无法找到明确的答案。
WITH RECURSIVE
PostgreSQL中的语法优化了多少?我的意思是:它仅仅是一系列非递归查询的语法糖,还是它更像是一个语句,尽管其复杂的语义已经作为一个整体进行了优化。一个后续问题 - 优化这种语法有多少可能?当然,欢迎提供有关此事的具体数据。
我发现它优化到了一定程度。
各种子查询按预期重复使用并单独优化,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;
在上面,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;
...并在主键上使用索引扫描。在实践中,它实际上会在 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;
另一个问题是您不能将 FOR UPDATE 与递归 CTE 一起使用(事实上,原因几乎相同)。
我的经验是它确实优化得很好。
查看由 EXPLAIN ANALYZE 生成的查询的执行计划,您会看到它实际上是多么“昂贵”(然后将其与自写的递归函数进行比较)