Datos de muestra dados:
create table results ( commandid integer primary key);
insert into results (commandid) select * from generate_series(1,1000);
delete from results where random() < 0.20;
Esto funciona:
SELECT s.i AS missing_cmd
FROM generate_series(0,1000) s(i)
WHERE NOT EXISTS (SELECT 1 FROM results WHERE commandid = s.i);
al igual que esta formulación 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;
Ambos de los anteriores parecen dar como resultado planes de consulta idénticos en mis pruebas, pero debe comparar con sus datos en su base de datos usando EXPLAIN ANALYZE
para ver cuál es mejor.
Explicación
Tenga en cuenta que en lugar de NOT IN
He usado NOT EXISTS
con una subconsulta en una formulación y un OUTER JOIN
ordinario en el otro. Es mucho más fácil para el servidor de base de datos optimizarlos y evita los problemas confusos que pueden surgir con NULL
s en NOT IN
.
Inicialmente favorecí OUTER JOIN
formulación, pero al menos en 9.1 con mis datos de prueba el NOT EXISTS
el formulario se optimiza al mismo plan.
Ambos funcionarán mejor que el NOT IN
siguiente formulación cuando la serie es grande, como en su caso. NOT IN
solía requerir que Pg hiciera una búsqueda lineal de IN
lista para cada tupla que se está probando, pero el examen del plan de consulta sugiere que Pg puede ser lo suficientemente inteligente como para codificarlo ahora. El NOT EXISTS
(transformado en JOIN
por el planificador de consultas) y JOIN
trabajar mejor.
El NOT IN
la formulación es confusa en presencia de NULL commandid
s y puede ser ineficiente:
SELECT s.i AS missing_cmd
FROM generate_series(0,1000) s(i)
WHERE s.i NOT IN (SELECT commandid FROM results);
así que lo evitaría. Con 1 000 000 de filas, los otros dos se completaron en 1,2 segundos y el NOT IN
la formulación se ejecutó vinculada a la CPU hasta que me aburrí y la cancelé.