Obrovský IN
seznam je velmi neefektivní. PostgreSQL by jej měl ideálně identifikovat a převést na relaci, u které provede anti-join, ale v tomto okamžiku plánovač dotazů neví, jak to udělat, a čas plánování potřebný k identifikaci tohoto případu by stál každý dotaz, který používá NOT IN
rozumně, takže by to musela být kontrola s velmi nízkými náklady. Viz tuto dřívější mnohem podrobnější odpověď na toto téma
.
Jak napsal David Aldridge, toto se nejlépe vyřeší tak, že se to změní na anti-join. Napsal bych to jako spojení přes VALUES
seznam jednoduše proto, že PostgreSQL je extrémně rychlý při analýze VALUES
uvádí do vztahů, ale efekt je stejný:
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;
Pro dostatečně velkou sadu hodnot může být dokonce lepší vytvořit dočasnou tabulku COPY
vložením hodnot do něj vytvoříte PRIMARY KEY
na to a připojit se k tomu.
Další možnosti prozkoumány zde:
https://stackoverflow.com/a/17038097/398670