sql >> Databasteknik >  >> RDS >> PostgreSQL

Ta bort med CTE långsammare än att använda temptabell i Postgres

CTE är långsammare eftersom det måste utföras oförändrat (via en CTE-skanning).

TFM (avsnitt 7.8.2) säger: Datamodifierande uttalanden i WITH exekveras exakt en gång, och alltid till komplettering, oberoende av om den primära frågan läser alla (eller faktiskt någon) av deras utdata. Observera att detta skiljer sig från regeln för SELECT i WITH:som nämnts i föregående avsnitt, körning av en SELECT är utförs endast så långt som den primära frågan kräver dess utdata.

Det är alltså en optimeringsbarriär; för optimeraren är det inte tillåtet att demontera CTE, även om det skulle resultera i en smartare plan med samma resultat.

CTE-lösningen kan dock omstruktureras till en sammanfogad underfråga (liknande temptabellen i frågan). I postgres är en sammanfogad underfråga vanligtvis snabbare än varianten EXISTS() nuförtiden.

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
        ;

Ett annat sätt är att använda en TEMP VIEW . Detta är syntaktisk motsvarande temp table fall, men semantiskt likvärdigt med det sammanfogade underfrågeformuläret (de ger exakt samma frågeplan, åtminstone i det här fallet). Detta beror på att Postgress optimerare demonterar vyn och kombinerar den med huvudfrågan (pull-up ). Du kan se en view som ett slags makro i 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
        );

[UPPDATERAD:Jag hade fel om att CTE alltid måste utföras till slutförande, vilket bara är fallet för datamodifierande CTE]



  1. Att skjuta upp frekventa uppdateringar i MySQL

  2. MONGODB Mongoimport möjlig påskynda?

  3. Failover-stöd för en DB

  4. Hur kan jag göra en INNAN UPPDATERAD trigger med sql-server?