Instrukcja WITH (lub CTE — Common Table Expression) tymczasowo tworzy zbiór wyników, który można wykorzystać w głównym SELECT lub nawet rekurencyjnie. CTE upraszczają zapytania do zrozumienia, zwiększają czytelność i pozwalają na ponowne wykorzystanie pośrednich wyników.
Zalety w porównaniu do zwykłych podzapytań:
Przykład:
WITH high_salary AS ( SELECT id, name FROM employees WHERE salary > 100000 ) SELECT * FROM high_salary WHERE name LIKE 'A%';
“Czy ważne jest wskazanie MATERIALIZED/NOT MATERIALIZED podczas deklarowania CTE? Jak może to wpłynąć na wydajność?”
Odpowiedź: W PostgreSQL można wyraźnie wskazać MATERIALIZED (zawsze obliczać CTE raz i przechowywać, nawet jeśli jest używane kilka razy) lub NOT MATERIALIZED (CTE będzie inline w głównym zapytaniu). Zazwyczaj optymalizator sam decyduje, czy warto materializować CTE, ale wymuszenie tego czasami znacząco wpływa na szybkość.
Przykład:
WITH high_salary AS MATERIALIZED ( SELECT id, name FROM employees WHERE salary > 100000 ) SELECT * FROM high_salary WHERE name LIKE 'A%';
Historia
W dużym projekcie analityk wymienił wszystkie podzapytań na CTE, nie wiedząc, że w PostgreSQL przed wersją 12 CTE zawsze były materializowane. Wynik — zapytania zwolniły się 2-3 razy. Po powrocie do podzapytań lub przejściu na nowe wersje problem zniknął.
Historia
Raport z kilkoma poziomami zagnieżdżonych podzapytań stał się nieczytelny dla kolegi. Przepisałem na CTE o zrozumiałych nazwach — dyskusje i wsparcie zapytań znacznie się uprościły.
Historia
Dwa CTE o identycznych nazwach wywołały zamieszanie w dużym skrypcie: CTE było używane jeszcze przed jego deklaracją. W rezultacie — błąd kompilacji i duża strata czasu na szukanie przyczyny.