Postgres реализует то, что называется «оптимизационным ограждением» для CTE.Это означает, что Postgres материализует каждый CTE для последующей обработки.Одним приятным эффектом является то, что на CTE можно ссылаться несколько раз, но код выполняется только один раз.Недостатком является то, что такие удобства, как указатели, «забываются» после того, как CTE материализован.
По вашему вопросу, представление на самом деле несущественно (без каламбура).В этой версии:
WITH cte AS (
SELECT first, middle, last FROM user WHERE user_id = 5
),
cte2 AS (
SELECT *, first || middle AS first_middle FROM cte
),
cte3 AS (
SELECT *, first_middle || last AS full_name FROM cte2
)
SELECT *
FROM cte3;
Первый CTE предположительно вытаскивает одну запись из таблицы.Предположительно, он использует индекс по идентификатору, и даже эта операция выполняется очень быстро.Эта одна запись является единственной записью, обработанной оставшимися CTE.
В этой версии:
WITH cte AS (
SELECT first, middle, last FROM user
),
cte2 AS (
SELECT *, first || middle AS first_middle FROM cte
),
cte3 AS (
SELECT *, first_middle || last AS full_name FROM cte2
)
SELECT *
FROM cte3
WHERE user_id = 5;
CTE обрабатывают все данные в user
Таблица.В конце должна быть найдена строка, соответствующая условию WHERE
.Материализованный CTE больше не имеет индекса.,,поэтому данные ищутся последовательно.
Это поведение не применимо к подзапросам, поэтому вы можете попробовать переписать логику, используя подзапросы, а не CTE.
Postgres оптимизирует CTE по-разномуиз других баз данных.Например, SQL Server никогда не материализует подзапросы;код всегда «вставляется» в запрос и оптимизируется в целом.На самом деле форумы по SQL Server имеют противоположную задачу - реализовать возможность материализации CTE.отличается от других баз данных.Oracle - это одна база данных, которая, похоже, использует оба подхода.