Givet exempeldata:
create table results ( commandid integer primary key);
insert into results (commandid) select * from generate_series(1,1000);
delete from results where random() < 0.20;
Detta fungerar:
SELECT s.i AS missing_cmd
FROM generate_series(0,1000) s(i)
WHERE NOT EXISTS (SELECT 1 FROM results WHERE commandid = s.i);
liksom denna alternativa 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;
Båda ovanstående verkar resultera i identiska frågeplaner i mina tester, men du bör jämföra med dina data i din databas med EXPLAIN ANALYZE
för att se vilken som är bäst.
Förklaring
Observera att istället för NOT IN
Jag har använt NOT EXISTS
med en underfråga i en formulering och en vanlig OUTER JOIN
i den andra. Det är mycket lättare för DB-servern att optimera dessa och den undviker de förvirrande problem som kan uppstå med NULL
s i NOT IN
.
Jag föredrog först OUTER JOIN
formulering, men åtminstone i 9.1 med mina testdata NOT EXISTS
form optimerar till samma plan.
Båda kommer att fungera bättre än NOT IN
formulering nedan när serien är stor, som i ditt fall. NOT IN
används för att kräva att Pg gör en linjär sökning av IN
lista för varje tuppel som testas, men granskning av frågeplanen tyder på att Pg kan vara smart nog att hasha den nu. NOT EXISTS
(omvandlas till en JOIN
av frågeplaneraren) och JOIN
fungera bättre.
NOT IN
formulering är både förvirrande i närvaro av NULL commandid
s och kan vara ineffektiva:
SELECT s.i AS missing_cmd
FROM generate_series(0,1000) s(i)
WHERE s.i NOT IN (SELECT commandid FROM results);
så jag skulle undvika det. Med 1 000 000 rader klarade de andra två på 1,2 sekunder och NOT IN
Formuleringen körde CPU-bunden tills jag blev uttråkad och avbröt den.