CTE е по-бавен, защото трябва да се изпълни непроменен (чрез CTE сканиране).
Следователно това е пречка за оптимизиране; за оптимизатора демонтирането на CTE не е разрешено, дори ако това би довело до по-интелигентен план със същите резултати.
CTE-решението обаче може да бъде преработено в обединена подзаявка (подобно на временната таблица във въпроса). В postgres обединената подзаявка обикновено е по-бърза от варианта 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
;
Друг начин е да използвате TEMP VIEW
. Това е синтактично еквивалентно на temp table
случай, но семантично еквивалентно на присъединения формуляр за подзаявка (те дават точно същият план за заявка, поне в този случай). Това е така, защото оптимизаторът на Postgres демонтира изгледа и го комбинира с основната заявка (издърпване ). Можете да видите view
като вид макрос в 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
);
[АКТУАЛИЗИРАНО:Сгреших относно необходимостта от CTE винаги да се изпълняват до завършване, което важи само за CTE, модифициращи данни]