PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

PostgreSQL:Wie finde ich fehlende Zahlen in einer Spalte mit generate_series() heraus?

Gegebene Beispieldaten:

create table results ( commandid integer primary key);
insert into results (commandid) select * from generate_series(1,1000);
delete from results where random() < 0.20;

Das funktioniert:

SELECT s.i AS missing_cmd
FROM generate_series(0,1000) s(i)
WHERE NOT EXISTS (SELECT 1 FROM results WHERE commandid = s.i);

ebenso wie diese alternative Formulierung:

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;

Beides scheint in meinen Tests zu identischen Abfrageplänen zu führen, aber Sie sollten mit EXPLAIN ANALYZE mit Ihren Daten in Ihrer Datenbank vergleichen um zu sehen, welches am besten ist.

Erklärung

Beachten Sie, dass anstelle von NOT IN Ich habe NOT EXISTS verwendet mit einer Unterabfrage in einer Formulierung und einem gewöhnlichen OUTER JOIN in dem anderen. Es ist für den DB-Server viel einfacher, diese zu optimieren, und vermeidet die verwirrenden Probleme, die mit NULL auftreten können s in NOT IN .

Anfangs favorisierte ich den OUTER JOIN Formulierung, aber zumindest in 9.1 mit meinen Testdaten ist der NOT EXISTS Formular optimiert auf denselben Plan.

Beide werden besser abschneiden als NOT IN Formulierung unten, wenn die Serie groß ist, wie in Ihrem Fall. NOT IN früher verlangte, dass Pg eine lineare Suche nach IN durchführte list für jedes getestete Tupel auf, aber eine Untersuchung des Abfrageplans legt nahe, dass Pg schlau genug sein könnte, es jetzt zu hashen. Der NOT EXISTS (umgewandelt in einen JOIN durch den Abfrageplaner) und den JOIN besser funktionieren.

Der NOT IN Formulierung ist sowohl in Gegenwart von NULL commandid verwirrend s und kann ineffizient sein:

SELECT s.i AS missing_cmd
FROM generate_series(0,1000) s(i)
WHERE s.i NOT IN (SELECT commandid FROM results);

also ich würde es vermeiden. Mit 1.000.000 Zeilen waren die anderen beiden in 1,2 Sekunden fertig und der NOT IN Formulierung lief CPU-gebunden, bis ich mich langweilte und sie abbrach.