Givet eksempeldata:
create table results ( commandid integer primary key);
insert into results (commandid) select * from generate_series(1,1000);
delete from results where random() < 0.20;
Dette virker:
SELECT s.i AS missing_cmd
FROM generate_series(0,1000) s(i)
WHERE NOT EXISTS (SELECT 1 FROM results WHERE commandid = s.i);
ligesom denne alternative 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;
Begge ovenstående ser ud til at resultere i identiske forespørgselsplaner i mine tests, men du bør sammenligne med dine data på din database ved hjælp af EXPLAIN ANALYZE
for at se, hvilken der er bedst.
Forklaring
Bemærk, at i stedet for NOT IN
Jeg har brugt EKSISTERER IKKE
med en underforespørgsel i én formulering og en almindelig OUTER JOIN
i den anden. Det er meget nemmere for DB-serveren at optimere disse, og det undgår de forvirrende problemer, der kan opstå med NULL
s i NOT IN
.
Jeg foretrak oprindeligt OUTER JOIN
formulering, men i det mindste i 9.1 med mine testdata EKSISTERER IKKE
form optimerer til den samme plan.
Begge vil fungere bedre end NOT IN
formulering nedenfor, når serien er stor, som i dit tilfælde. IKKE IN
bruges til at kræve, at Pg laver en lineær søgning i IN
liste for hver tuple, der testes, men undersøgelse af forespørgselsplanen tyder på, at Pg kan være smart nok til at hash det nu. JOIN
af forespørgselsplanlæggeren) og JOIN
arbejde bedre.
commandid
s og kan være ineffektiv:
SELECT s.i AS missing_cmd
FROM generate_series(0,1000) s(i)
WHERE s.i NOT IN (SELECT commandid FROM results);
så jeg ville undgå det. Med 1.000.000 rækker fuldførte de to andre på 1,2 sekunder og NOT IN
formulering kørte CPU-bundet, indtil jeg kedede mig og annullerede den.