Загружаем изображение…
PostgreSQL умеет замораживать часть запроса и запрещать оптимизатору его разворачивать!
Начиная с PostgreSQL 12 оптимизатор получил право разворачивать
Такой
Например, если внутри CTE дорогой расчёт, который нельзя выполнять повторно. Тут появляется малоизвестная фича:
А обратная фича:
наоборот подсказывает оптимизатору агрессивно встраивать
Одна и та же
SQL Ready | #совет
Начиная с PostgreSQL 12 оптимизатор получил право разворачивать
CTE прямо внутрь основного запроса.WITH data AS (
SELECT *
FROM orders
)
SELECT *
FROM data
WHERE user_id = 42;Такой
WITH может вообще исчезнуть из плана выполнения, потому что PostgreSQL встроит его обратно в запрос. Но иногда это плохо.Например, если внутри CTE дорогой расчёт, который нельзя выполнять повторно. Тут появляется малоизвестная фича:
WITH expensive AS MATERIALIZED (
SELECT *
FROM huge_events
WHERE created_at >= now() - interval '1 day'
)
SELECT COUNT(*)
FROM expensive;MATERIALIZED заставляет PostgreSQL сначала физически вычислить CTE, а потом использовать результат дальше.А обратная фича:
WITH data AS NOT MATERIALIZED (
SELECT *
FROM orders
)
SELECT *
FROM data
WHERE user_id = 42;наоборот подсказывает оптимизатору агрессивно встраивать
CTE обратно в запрос.Одна и та же
CTE с MATERIALIZED и без него иногда отличается по производительности в десятки раз на больших объёмах данных.SQL Ready | #совет