PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

PostgreSQL:come capire i numeri mancanti in una colonna usando generate_series()?

Dati di esempio dati:

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

Funziona:

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

così come questa formulazione alternativa:

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;

Entrambi i precedenti sembrano produrre piani di query identici nei miei test, ma dovresti confrontarli con i tuoi dati sul tuo database usando EXPLAIN ANALYZE per vedere qual è il migliore.

Spiegazione

Nota che invece di NOT IN Ho usato NOT EXISTS con una sottoquery in una formulazione e un normale OUTER JOIN nell'altro. È molto più facile per il server DB ottimizzarli ed evita i problemi di confusione che possono sorgere con NULL s in NOT IN .

Inizialmente ho preferito OUTER JOIN formulazione, ma almeno in 9.1 con i miei dati di prova il NOT EXISTS il modulo viene ottimizzato per lo stesso piano.

Entrambi avranno prestazioni migliori rispetto a NOT IN formulazione di seguito quando la serie è grande, come nel tuo caso. NOT IN utilizzato per richiedere a Pg di eseguire una ricerca lineare di IN list per ogni tupla in fase di test, ma l'esame del piano di query suggerisce che Pg potrebbe essere abbastanza intelligente da eseguire l'hashing ora. Il NOT EXISTS (trasformato in un JOIN dal pianificatore di query) e il JOIN funziona meglio.

Il NOT IN la formulazione crea confusione in presenza di NULL commandid se può essere inefficiente:

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

quindi lo eviterei Con 1.000.000 di righe le altre due completavano in 1,2 secondi e il NOT IN la formulazione è stata eseguita con la CPU fino a quando non mi sono annoiato e l'ho annullato.