CTE jest wolniejsze, ponieważ musi być wykonywane bez zmian (poprzez skanowanie CTE).
Jest to zatem bariera optymalizacji; dla optymalizatora demontaż CTE jest niedozwolony, nawet jeśli skutkowałoby to mądrzejszym planem z takimi samymi wynikami.
Rozwiązanie CTE można jednak przekształcić w połączone podzapytanie (podobnie do tabeli tymczasowej w pytaniu). W postgresie połączone podzapytanie jest zwykle szybsze niż obecnie dostępny wariant EXISTS().
DELETE FROM customer del
USING ( SELECT id
, row_number() over(partition by uuid order by created_date desc)
as rn
FROM customer
) sub
WHERE sub.id = del.id
AND sub.rn > 1
;
Innym sposobem jest użycie TEMP VIEW
. To jest syntaktycznie odpowiednik temp table
przypadku, ale semantycznie odpowiednik połączonego formularza podzapytania (dają dokładnie ten sam plan zapytań, przynajmniej w tym przypadku). Dzieje się tak, ponieważ optymalizator Postgresa demontuje widok i łączy go z głównym zapytaniem (pull-up ). Możesz zobaczyć view
jako rodzaj makra w PG.
CREATE TEMP VIEW targets
AS SELECT id
, row_number() over(partition by uuid ORDER BY created_date DESC) AS rn
FROM customer;
EXPLAIN
DELETE FROM customer
WHERE id IN ( SELECT id
FROM targets
WHERE rn > 1
);
[AKTUALIZACJA:Myliłem się co do tego, że CTE muszą być zawsze wykonywane do zakończenia, co ma miejsce tylko w przypadku modyfikacji danych CTE]