Un énorme IN
liste est très inefficace. PostgreSQL devrait idéalement l'identifier et le transformer en une relation sur laquelle il effectue une anti-jointure, mais à ce stade, le planificateur de requêtes ne sait pas comment faire cela, et le temps de planification requis pour identifier ce cas coûterait à chaque requête qui utilise NOT IN
raisonnablement, il faudrait donc que ce soit un contrôle à très faible coût. Voir cette réponse précédente beaucoup plus détaillée sur le sujet
.
Comme l'a écrit David Aldridge, le mieux est de le résoudre en le transformant en anti-jointure. Je l'écrirais comme une jointure sur un VALUES
list simplement parce que PostgreSQL est extrêmement rapide pour analyser VALUES
listes en relations, mais l'effet est le même :
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;
Pour un ensemble de valeurs suffisamment grand, vous feriez peut-être même mieux de créer une table temporaire, COPY
en y insérant les valeurs, en créant une PRIMARY KEY
dessus, et se joindre à cela.
Plus de possibilités explorées ici :
https://stackoverflow.com/a/17038097/398670