Gegeven voorbeeldgegevens:
create table results ( commandid integer primary key);
insert into results (commandid) select * from generate_series(1,1000);
delete from results where random() < 0.20;
Dit werkt:
SELECT s.i AS missing_cmd
FROM generate_series(0,1000) s(i)
WHERE NOT EXISTS (SELECT 1 FROM results WHERE commandid = s.i);
net als deze alternatieve formulering:
SELECT s.i AS missing_cmd
FROM generate_series(0,1000) s(i)
LEFT OUTER JOIN results ON (results.commandid = s.i)
WHERE results.commandid IS NULL;
Beide bovenstaande lijken te resulteren in identieke queryplannen in mijn tests, maar u moet deze vergelijken met uw gegevens in uw database met behulp van EXPLAIN ANALYZE
om te zien welke het beste is.
Uitleg
Merk op dat in plaats van NOT IN
Ik heb NOT EXISTS
gebruikt met een subquery in één formulering en een gewone OUTER JOIN
in de andere. Het is veel gemakkelijker voor de DB-server om deze te optimaliseren en het vermijdt de verwarrende problemen die kunnen optreden met NULL
s in NOT IN
.
Ik gaf aanvankelijk de voorkeur aan de OUTER JOIN
formulering, maar in ieder geval in 9.1 met mijn testgegevens de NOT EXISTS
formulier optimaliseert naar hetzelfde plan.
Beide zullen beter presteren dan de NOT IN
formulering hieronder wanneer de reeks groot is, zoals in uw geval. NOT IN
gebruikt om Pg te verplichten om een lineaire zoekopdracht uit te voeren van de IN
lijst voor elke tuple die wordt getest, maar onderzoek van het queryplan suggereert dat Pg misschien slim genoeg is om het nu te hashen. De NOT EXISTS
(omgevormd tot een JOIN
door de queryplanner) en de JOIN
beter werken.
De NOT IN
formulering is zowel verwarrend in de aanwezigheid van NULL commandid
s en kan inefficiënt zijn:
SELECT s.i AS missing_cmd
FROM generate_series(0,1000) s(i)
WHERE s.i NOT IN (SELECT commandid FROM results);
dus ik zou het vermijden. Met 1.000.000 rijen voltooiden de andere twee in 1,2 seconden en de NOT IN
formulering liep CPU-gebonden totdat ik me verveelde en het annuleerde.