J'ai l'a trouvé optimisé jusqu'à un certain point.
Les différentes sous-requêtes sont réutilisées comme prévu et optimisées individuellement, et Postgres optimise ce dernier comme n'importe quelle autre requête. Mon principal reproche avec cela a à voir avec le fait qu'il n'injectera pas de contraintes dans les CTE quand il le pourrait.
Par exemple:
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 comprendrait idéalement, dans ce qui précède, que (depuis node.id est retourné comme est) qu'il peut faire:
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;
... et utilisez un scan d'index sur la clé primaire. En pratique, cela fonctionnera exactement lorsque le CTE lui dira de faire: tirez récursivement tous les parents pour toutes les lignes, placez le jeu de résultats dans une table temporaire sans nom si nécessaire, puis vérifiez chaque ligne du jeu de résultats un pour id = En d'autres termes, un CTE ne garde pas une trace de l'ensemble table/ligne/colonne "originaire" qu'il retourne. Jusqu'à ce que cela soit optimisé correctement, créer une vue sur une requête récursive est au mieux fou.
Une bonne solution entre-temps est de créer une fonction sql à la place:
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;
Un autre problème est que vous ne pouvez pas utiliser FOR UPDATE avec CTEs récursif (pour très bien la même raison, en fait).
La raison d'avoir 'WITH RECURSIVE' au niveau du langage est que la base de données sait ce que vous essayez de faire et peut agir en fonction de votre intention. –
@mu Oui, eh bien c'est ce que j'ai compté. Cependant, il n'est pas évident de savoir comment il pourrait par exemple être optimisé simplement en utilisant des indices et même au niveau de la base de données. Certaines opérations sont juste difficiles en général. Suite à la suggestion, je posterai mes résultats dès que j'aurai terminé. – julkiewicz
@julkiewicz Une table de fermeture transitive est en effet un index pour de telles requêtes. Je ne vois aucune raison qu'un type d'index ne puisse pas être proposé utilisant des techniques similaires. – EricS