sql >> Databasteknik >  >> RDS >> PostgreSQL

PostgreSQL:Hur tar man reda på saknade tal i en kolumn med generera_serier()?

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.



  1. Snabbaste sättet att subset - data.table vs. MySQL

  2. ODP.NET Integrated Security Ogiltigt anslutningssträngargument

  3. Lagra datum-tid-data som siffror

  4. EXECUTE av SELECT ... INTO är inte implementerat