PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Postgres NICHT IN Leistung

Ein riesiges IN Liste ist sehr ineffizient. PostgreSQL sollte es idealerweise identifizieren und in eine Beziehung umwandeln, für die es einen Anti-Join durchführt, aber an diesem Punkt weiß der Abfrageplaner nicht, wie das geht, und die Planungszeit, die erforderlich ist, um diesen Fall zu identifizieren, würde jede Abfrage so viel kosten verwendet NOT IN vernünftigerweise, also müsste es ein sehr kostengünstiger Scheck sein. Siehe diese frühere viel ausführlichere Antwort zu diesem Thema .

Wie David Aldridge schrieb, lässt sich dies am besten lösen, indem man es in einen Anti-Join umwandelt. Ich würde es als Join über VALUES schreiben einfach deshalb auflisten, weil PostgreSQL beim Parsen von VALUES extrem schnell ist Listen in Relationen, aber der Effekt ist derselbe:

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; 

Für einen ausreichend großen Satz von Werten ist es vielleicht sogar besser, eine temporäre Tabelle zu erstellen, COPY ing die Werte hinein und erzeugt einen PRIMARY KEY darauf und schließe mich dem an.

Weitere Möglichkeiten wurden hier erkundet:

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