PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Postgres PAS EN performances

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