sql >> Database >  >> RDS >> PostgreSQL

Verwijderen met behulp van CTE langzamer dan het gebruik van de tijdelijke tabel in Postgres

De CTE is langzamer omdat deze ongewijzigd moet worden uitgevoerd (via een CTE-scan).

TFM (paragraaf 7.8.2) stelt: Gegevensmodificerende instructies in WITH worden uitgevoerd precies één keer, en altijd tot voltooiing, ongeacht of de primaire query alle (of zelfs een deel ervan) van hun uitvoer leest. Merk op dat dit verschilt van de regel voor SELECT in WITH:zoals vermeld in de vorige sectie, is het uitvoeren van een SELECT alleen uitgevoerd voor zover de primaire query de uitvoer ervan vereist.

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]



  1. Oracle-query - ORA-01652:kan het tijdelijke segment niet uitbreiden, maar alleen in sommige versies van sql*plus

  2. String splitsen op positie van scheidingsteken met behulp van Oracle SQL

  3. verander database (postgresql) in python met behulp van psycopg2 dynamisch

  4. MySQL:hoe fulltext zoeken in meerdere tabellen te maken