Я нашел его оптимизированным до определенного момента.
Различные подзапросы используются повторно, как и ожидалось, и оптимизируются индивидуально, а 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 (фактически, по той же причине).