En enorm IN
listen er meget ineffektiv. PostgreSQL burde ideelt set identificere det og gøre det til en relation, som det gør en anti-join på, men på dette tidspunkt ved forespørgselsplanlæggeren ikke, hvordan man gør det, og den planlægningstid, der kræves til at identificere denne sag, ville koste hver forespørgsel, der bruger NOT IN
fornuftigt, så det må være en meget billig kontrol. Se dette tidligere meget mere detaljerede svar om emnet
.
Som David Aldridge skrev, løses dette bedst ved at gøre det til en anti-join. Jeg ville skrive det som en joinforbindelse over en VALUES
liste, simpelthen fordi PostgreSQL er ekstremt hurtig til at parse VALUES
lister ind i relationer, men effekten er den samme:
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;
For et tilstrækkeligt stort sæt værdier kan du endda være bedre stillet at oprette en midlertidig tabel, COPY
ved at indsætte værdierne i det, skabe en PRIMARY KEY
på det, og slutte sig til det.
Flere muligheder undersøgt her:
https://stackoverflow.com/a/17038097/398670