Data sampel yang diberikan:
create table results ( commandid integer primary key);
insert into results (commandid) select * from generate_series(1,1000);
delete from results where random() < 0.20;
Ini berfungsi:
SELECT s.i AS missing_cmd
FROM generate_series(0,1000) s(i)
WHERE NOT EXISTS (SELECT 1 FROM results WHERE commandid = s.i);
seperti halnya formulasi alternatif ini:
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;
Kedua hal di atas tampaknya menghasilkan rencana kueri yang identik dalam pengujian saya, tetapi Anda harus membandingkan dengan data Anda di database menggunakan EXPLAIN ANALYZE
untuk melihat mana yang terbaik.
Penjelasan
Perhatikan bahwa alih-alih NOT IN
Saya telah menggunakan NOT EXISTS
dengan subquery dalam satu formulasi, dan OUTER JOIN
biasa di lain. Jauh lebih mudah bagi server DB untuk mengoptimalkan ini dan menghindari masalah membingungkan yang dapat muncul dengan NULL
s di NOT IN
.
Saya awalnya menyukai OUTER JOIN
formulasi, tetapi setidaknya dalam 9.1 dengan data pengujian saya NOT EXISTS
formulir dioptimalkan untuk rencana yang sama.
Keduanya akan berkinerja lebih baik daripada NOT IN
formulasi di bawah ini ketika seri besar, seperti dalam kasus Anda. NOT IN
digunakan untuk meminta Pg untuk melakukan pencarian linier dari IN
list untuk setiap tuple yang sedang diuji, tetapi pemeriksaan rencana kueri menunjukkan bahwa Pg mungkin cukup pintar untuk melakukan hashing sekarang. NOT EXISTS
(diubah menjadi JOIN
oleh perencana kueri) dan JOIN
bekerja lebih baik.
NOT IN
formulasi keduanya membingungkan dengan adanya NULL commandid
s dan bisa menjadi tidak efisien:
SELECT s.i AS missing_cmd
FROM generate_series(0,1000) s(i)
WHERE s.i NOT IN (SELECT commandid FROM results);
jadi saya akan menghindarinya. Dengan 1.000.000 baris, dua lainnya selesai dalam 1,2 detik dan NOT IN
formulasi menjalankan CPU-bound sampai saya bosan dan membatalkannya.