De CTE is langzamer omdat deze ongewijzigd moet worden uitgevoerd (via een CTE-scan).
Het is dus een optimalisatiebarrière; voor de optimizer is het ontmantelen van de CTE niet toegestaan, ook al zou dit leiden tot een slimmer plan met hetzelfde resultaat.
De CTE-oplossing kan echter worden omgezet in een samengevoegde subquery (vergelijkbaar met de tijdelijke tabel in de vraag). In postgres is een samengevoegde subquery tegenwoordig meestal sneller dan de EXISTS()-variant.
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
;
Een andere manier is om een TEMP VIEW
. te gebruiken . Dit is syntactisch gelijk aan de temp table
hoofdlettergebruik, maar semantisch equivalent aan het samengevoegde subqueryformulier (ze geven exact hetzelfde queryplan, althans in dit geval). Dit komt omdat de optimiser van Postgres ontmantelt de weergave en combineert deze met de hoofdquery (pull-up ). Je zou een view
kunnen zien als een soort macro in 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
);
[UPDATE:ik had het mis over de CTE's die altijd moeten worden uitgevoerd om te voltooien, wat alleen het geval is voor CTE's die gegevens wijzigen]