El CTE es más lento porque debe ejecutarse sin cambios (a través de un escaneo CTE).
Por lo tanto, es una barrera de optimización; para el optimizador, no está permitido desmantelar el CTE, incluso si resultaría en un plan más inteligente con los mismos resultados.
Sin embargo, la solución CTE se puede refactorizar en una subconsulta unida (similar a la tabla temporal en la pregunta). En Postgres, una subconsulta unida suele ser más rápida que la variante EXISTS(), hoy en día.
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
;
Otra forma es usar una TEMP VIEW
. Esto es sintácticamente equivalente a la temp table
caso, pero semánticamente equivalente al formulario de subconsulta unida (producen exactamente el mismo plan de consulta, al menos en este caso). Esto se debe a que el optimizador de Postgres desmantela la vista y la combina con la consulta principal (pull-up ). Podrías ver una view
como una especie de macro en 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
);
[ACTUALIZADO:Me equivoqué acerca de que los CTE deben ejecutarse siempre hasta su finalización, que es solo el caso de CTE de modificación de datos]