sql >> Database teknologi >  >> RDS >> PostgreSQL

Slet ved at bruge CTE langsommere end at bruge temp table i Postgres

CTE'en er langsommere, fordi den skal udføres uændret (via en CTE-scanning).

TFM (afsnit 7.8.2) siger: Datamodificerende sætninger i WITH udføres præcis én gang, og altid til afslutning, uafhængigt af om den primære forespørgsel læser alt (eller faktisk noget) af deres output. Bemærk, at dette er forskelligt fra reglen for SELECT i WITH:som angivet i det foregående afsnit er udførelse af en SELECT udføres kun så vidt den primære forespørgsel kræver sit output.

Det er således en optimeringsbarriere; for optimizeren er det ikke tilladt at afmontere CTE, selvom det ville resultere i en smartere plan med de samme resultater.

CTE-løsningen kan dog omdannes til en samlet underforespørgsel (svarende til temp-tabellen i spørgsmålet). I postgres er en sammenføjet underforespørgsel normalt hurtigere end EXISTS()-varianten i dag.

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
        ;

En anden måde er at bruge en TEMP VIEW . Dette er syntaktisk svarende til temp table case, men semantisk svarende til den samlede underforespørgselsformular (de giver præcis den samme forespørgselsplan, i det mindste i dette tilfælde). Dette skyldes, at Postgres' optimering afmonteres visningen og kombinerer den med hovedforespørgslen (pull-up ). Du kunne se en view som en 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
        );

[OPDATERET:Jeg tog fejl om, at CTE'er altid skal udføres-til-fuldførelse, hvilket kun er tilfældet for datamodificerende CTE'er]



  1. er der nogen måde at logge alle mislykkede sql-sætninger i oracle 10g

  2. Hvordan kontrollerer man, om en variabel er NULL, og sætter den derefter med en MySQL-lagret procedure?

  3. oracle call lagret procedure i vælg

  4. Hvorfor er '2'> '10'?