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

Postgres NON IN performance

Un enorme IN elenco è molto inefficiente. PostgreSQL idealmente dovrebbe identificarlo e trasformarlo in una relazione su cui esegue un anti-join, ma a questo punto il pianificatore di query non sa come farlo e il tempo di pianificazione richiesto per identificare questo caso costerebbe ogni query che utilizza NOT IN ragionevolmente, quindi dovrebbe essere un controllo a basso costo. Vedi questa precedente risposta molto più dettagliata sull'argomento .

Come ha scritto David Aldridge, è meglio risolverlo trasformandolo in un anti-join. Lo scriverei come join su un VALUES list semplicemente perché PostgreSQL è estremamente veloce nell'analisi di VALUES elenca in relazioni, ma l'effetto è lo stesso:

SELECT entityid 
FROM entity e
LEFT JOIN level1entity l1 ON l.level1id = e.level1_level1id
LEFT JOIN level2entity l2 ON l2.level2id = l1.level2_level2id
LEFT OUTER JOIN (
    VALUES
    (1377776),(1377792),(1377793),(1377794),(1377795),(1377796)
) ex(ex_entityid) ON (entityid = ex_entityid)
WHERE l2.userid = 'a987c246-65e5-48f6-9d2d-a7bcb6284c8f' 
AND ex_entityid IS NULL; 

Per un insieme di valori sufficientemente ampio potresti anche essere meglio creare una tabella temporanea, COPY inserendo i valori al suo interno, creando una PRIMARY KEY su di esso, e unirmi a quello.

Altre possibilità esplorate qui:

https://stackoverflow.com/a/17038097/398670