Apa perbedaan antara TIDAK ADA vs. TIDAK DALAM vs. KIRI GABUNG DI MANA NULL?

151

Tampak bagi saya bahwa Anda dapat melakukan hal yang sama dalam query SQL menggunakan BUKAN ADA, BUKAN DALAM, atau KIRI BERGABUNG DI MANA NULL. Sebagai contoh:

SELECT a FROM table1 WHERE a NOT IN (SELECT a FROM table2)

SELECT a FROM table1 WHERE NOT EXISTS (SELECT * FROM table2 WHERE table1.a = table2.a)

SELECT a FROM table1 LEFT JOIN table2 ON table1.a = table2.a WHERE table1.a IS NULL

Saya tidak yakin apakah saya sudah mendapatkan semua sintaks yang benar, tetapi ini adalah teknik umum yang saya lihat. Mengapa saya memilih untuk menggunakan salah satu dari yang lain? Apakah kinerjanya berbeda ...? Yang mana yang paling cepat / paling efisien? (Jika itu tergantung pada implementasi, kapan saya akan menggunakan masing-masing?)

froadie
sumber
6
Banyak mesin SQL umum memberi Anda kemampuan untuk melihat rencana eksekusi. Anda sering dapat menemukan perbedaan yang signifikan dalam efisiensi untuk kueri yang setara secara logis dengan cara ini. Keberhasilan metode apa pun tergantung pada faktor-faktor seperti ukuran tabel, indeks apa yang ada, dan lain-lain.
Chris Farmer
2
@wich: tidak ada database yang peduli tentang apa yang sebenarnya Anda kembalikan di dalam EXISTSklausa. Anda dapat kembali *, NULLatau apa pun: semua ini akan dioptimalkan jauh.
Quassnoi
2
@wich - mengapa? Keduanya di sini: techonthenet.com/sql/exists.php dan di sini: msdn.microsoft.com/en-us/library/ms188336.aspx tampaknya menggunakan * ...
froadie
8
@wich: ini bukan tentang "mengekspresikan minat". Ini tentang permintaan parser yang meminta Anda untuk meletakkan sesuatu di antara SELECTdan FROM. Dan *hanya lebih mudah untuk mengetik. Ya, SQLmemang memiliki kemiripan dengan bahasa alami, tetapi diurai dan dieksekusi oleh mesin, mesin yang diprogram. Bukannya itu akan tiba-tiba menerobos masuk ke dalam bilik Anda dan berteriak "berhenti menuntut bidang tambahan dalam EXISTSkueri karena saya muak mengurai mereka dan kemudian membuangnya!". Tidak apa-apa dengan komputer, sungguh.
Quassnoi
1
@Quassnoi jika Anda menulis kode hanya untuk tujuan mesin yang menerjemahkannya, kode itu akan terlihat mengerikan, dan sayangnya beberapa orang bekerja seperti itu. Namun, jika Anda menulis kode dalam optik lain, menulis kode untuk mengekspresikan apa yang Anda ingin mesin lakukan sebagai komunike dengan rekan-rekan Anda, Anda akan menulis kode yang lebih baik dan lebih terpelihara. Jadilah cerdas, tulis kode untuk orang, bukan untuk komputer.
yang

Jawaban:

139

Pendeknya:

NOT INsedikit berbeda: tidak pernah cocok jika hanya ada satu NULLdalam daftar.

  • Dalam MySQL, NOT EXISTSsedikit kurang efisien

  • Di SQL Server, LEFT JOIN / IS NULLkurang efisien

  • Di PostgreSQL, NOT INkurang efisien

  • Dalam Oracle, ketiga metode itu sama.

Quassnoi
sumber
1
Terima kasih atas tautannya! Dan terima kasih untuk ikhtisar singkat ... Kantor saya memblokir tautan karena beberapa alasan: P tapi saya akan memeriksanya segera setelah saya sampai di komputer biasa.
froadie
2
Hal lain adalah bahwa jika table1 .amengandung NULLsatu EXISTSpermintaan tidak akan kembali baris ini tetapi NOT INakan query jika table2kosong. BUKAN vs. TIDAK ADA Kolom yang Tidak Dapat Diabaikan: SQL Server
Martin Smith
@MartinSmith: NULL NOT IN ()dievaluasi ke true (tidak NULL), sama sepertiNOT EXISTS (NULL = column)
Quassnoi
2
@ Quassnoi - eh, Poin bagus, salah mengerti. The NOT EXISTSakan selalu kembali baris tapi NOT INhanya akan melakukannya jika sub query tidak mengembalikan baris.
Martin Smith
5

Jika database bagus dalam mengoptimalkan kueri, dua yang pertama akan ditransformasikan menjadi sesuatu yang dekat dengan yang ketiga.

Untuk situasi sederhana seperti yang ada di pertanyaan Anda, seharusnya ada sedikit atau tidak ada perbedaan, karena semuanya akan dieksekusi sebagai gabungan. Dalam kueri yang lebih kompleks, basis data mungkin tidak dapat membuat gabungan dari not indan not existskueri. Dalam hal ini permintaan akan jauh lebih lambat. Di sisi lain, gabungan juga dapat berkinerja buruk jika tidak ada indeks yang dapat digunakan, jadi hanya karena Anda menggunakan gabungan tidak berarti Anda aman. Anda harus memeriksa rencana pelaksanaan kueri untuk mengetahui apakah mungkin ada masalah kinerja.

Guffa
sumber
2

Dengan asumsi Anda menghindari nol, mereka semua cara menulis anti-bergabung menggunakan SQL Standar.

Kelalaian jelas setara dengan menggunakan EXCEPT:

SELECT a FROM table1
EXCEPT
SELECT a FROM table2

Catatan di Oracle Anda harus menggunakan MINUSoperator (bisa dibilang nama yang lebih baik):

SELECT a FROM table1
MINUS
SELECT a FROM table2

Berbicara tentang sintaksis berpemilik, mungkin ada ekuivalen non-standar yang layak diselidiki tergantung pada produk yang Anda gunakan misalnya OUTER APPLYdalam SQL Server (sesuatu seperti):

SELECT t1.a
  FROM table1 t1
       OUTER APPLY 
       (
        SELECT t2.a
          FROM table2 t2
         WHERE t2.a = t1.a
       ) AS dt1
 WHERE dt1.a IS NULL;
suatu hari nanti
sumber
0

Ketika perlu memasukkan data dalam tabel dengan kunci primer multi-bidang, pertimbangkan bahwa itu akan jauh lebih cepat (saya mencoba di Access tapi saya pikir di Database apa pun) untuk tidak memeriksa bahwa "tidak ada catatan dengan nilai 'seperti' dalam tabel", - bukan hanya memasukkan ke dalam tabel, dan catatan berlebih (dengan kunci) tidak akan dimasukkan dua kali.

baleks
sumber
0

Perspektif kinerja selalu menghindari penggunaan kata kunci terbalik seperti BUKAN DALAM, BUKAN ADA, ... Karena untuk memeriksa item terbalik, DBMS perlu menjalankan semua yang tersedia dan menjatuhkan pilihan terbalik.

Lahiru Cooray
sumber
1
Dan apa yang Anda usulkan sebagai solusi ketika Anda benar-benar membutuhkannya NOT?
ngobrol
Nah ketika tidak ada pilihan penyebab kita perlu menggunakan operasi TIDAK dan itulah sebabnya mereka ada. Praktik terbaik adalah menghindari mereka ketika kita memiliki solusi alternatif lain.
Lahiru Cooray
@onedaywhen, jika pengoptimal mengubah kueri dan mengembalikan hasil yang salah maka itu adalah bug
David דודו Markovitz
@ DuduMarkovitz: ya dan jika Anda menghubungi tim SQL Server dan mereka mengakui bug tetapi menolak untuk memperbaikinya karena mereka mengatakan hal itu dapat membuat kueri berjalan lebih lambat, maka itu adalah bug yang perlu Anda tangani .
onedaywhen
@onedaywhen - Ini bukan skenario hipotesis saya kira :-) Apakah Anda ingat rincian bug?
David Markודו Markovitz