Manakah dari pertanyaan ini yang lebih cepat?
TIDAK ADA:
SELECT ProductID, ProductName
FROM Northwind..Products p
WHERE NOT EXISTS (
SELECT 1
FROM Northwind..[Order Details] od
WHERE p.ProductId = od.ProductId)
Atau TIDAK DI:
SELECT ProductID, ProductName
FROM Northwind..Products p
WHERE p.ProductID NOT IN (
SELECT ProductID
FROM Northwind..[Order Details])
Rencana eksekusi permintaan mengatakan mereka berdua melakukan hal yang sama. Jika demikian, formulir mana yang disarankan?
Ini didasarkan pada database NorthWind.
[Sunting]
Baru saja menemukan artikel yang bermanfaat ini: http://weblogs.sqlteam.com/mladenp/archive/2007/05/18/60210.aspx
Saya pikir saya akan tetap dengan TIDAK ADA.
sql
sql-server
notin
ilitirit
sumber
sumber
NOT IN
pertanyaan ini :SELECT "A".* FROM "A" WHERE "A"."id" NOT IN (SELECT "B"."Aid" FROM "B" WHERE "B"."Uid" = 2)
hampir 30 kali lebih cepat dari iniNOT EXISTS
:SELECT "A".* FROM "A" WHERE (NOT (EXISTS (SELECT 1 FROM "B" WHERE "B"."user_id" = 2 AND "B"."Aid" = "A"."id")))
Jawaban:
Saya selalu default ke
NOT EXISTS
.Rencana eksekusi mungkin sama pada saat ini tetapi jika kolom baik diubah di masa depan untuk memungkinkan
NULL
sNOT IN
versi akan perlu melakukan lebih banyak pekerjaan (bahkan jika tidak adaNULL
s benar-benar hadir dalam data) dan semantikNOT IN
jikaNULL
s adalah hadir tidak mungkin menjadi yang Anda inginkan.Ketika tidak ada
Products.ProductID
atau[Order Details].ProductID
mengizinkanNULL
, makaNOT IN
akan diperlakukan secara identik dengan permintaan berikut.Paket persis dapat bervariasi tetapi untuk data contoh saya, saya mendapatkan yang berikut.
Kesalahpahaman yang cukup umum tampaknya adalah bahwa sub kueri yang berkorelasi selalu "buruk" dibandingkan dengan bergabung. Mereka pasti bisa ketika mereka memaksa rencana loop bersarang (sub-query dievaluasi baris demi baris) tetapi rencana ini termasuk operator anti gabung logis. Anti semi joins tidak terbatas pada loop bersarang tetapi dapat menggunakan hash atau gabungan (seperti dalam contoh ini) bergabung juga.
Jika
[Order Details].ProductID
adalahNULL
-Mampu query kemudian menjadiAlasan untuk ini adalah bahwa semantik yang benar jika
[Order Details]
berisiNULL
ProductId
s adalah untuk mengembalikan hasil. Lihat spool anti semi join tambahan dan baris untuk memverifikasi ini yang ditambahkan ke paket.Jika
Products.ProductID
juga diubah menjadiNULL
-able maka pertanyaannya menjadiAlasan untuk itu adalah karena a
NULL
Products.ProductId
tidak boleh dikembalikan dalam hasil kecuali jikaNOT IN
permintaan sub untuk mengembalikan hasil sama sekali (yaitu[Order Details]
tabel kosong). Dalam hal ini seharusnya. Dalam paket data sampel saya ini diterapkan dengan menambahkan anti semi join seperti di bawah ini.Efek dari ini ditunjukkan dalam posting blog yang sudah ditautkan oleh Buckley . Dalam contoh di sana jumlah bacaan logis meningkat dari sekitar 400 hingga 500.000.
Selain itu fakta bahwa satu
NULL
dapat mengurangi jumlah baris menjadi nol membuat estimasi kardinalitas sangat sulit. Jika SQL Server mengasumsikan bahwa ini akan terjadi tetapi pada kenyataannya tidak adaNULL
baris dalam data, sisa dari rencana eksekusi mungkin lebih buruk, jika ini hanya bagian dari permintaan yang lebih besar, dengan loop bersarang yang tidak tepat menyebabkan eksekusi berulang sub yang mahal pohon misalnya .Ini bukan satu-satunya rencana eksekusi mungkin untuk
NOT IN
padaNULL
kolom -Mampu namun. Artikel ini menunjukkan satu lagi untuk kueri terhadapAdventureWorks2008
basis data.Untuk
NOT IN
padaNOT NULL
kolom atau kolom yangNOT EXISTS
tidak dapat dibatalkan atau tidak dapat dibatalkan, kolom ini memberikan rencana berikut.Ketika kolom berubah menjadi
NULL
-able,NOT IN
rencana sekarang terlihat sepertiIni menambah operator join batin ekstra ke paket. Alat ini dijelaskan di sini . Itu semua ada untuk mengubah indeks berkorelasi tunggal sebelumnya mencari
Sales.SalesOrderDetail.ProductID = <correlated_product_id>
dua mencari per baris luar. Yang tambahan aktifWHERE Sales.SalesOrderDetail.ProductID IS NULL
.Karena ini berada di bawah anti semi join jika yang mengembalikan setiap baris pencarian kedua tidak akan terjadi. Namun jika
Sales.SalesOrderDetail
tidak mengandung apa punNULL
ProductID
, itu akan menggandakan jumlah operasi pencarian yang diperlukan.sumber
NOT EXISTS
berfungsi seperti yang saya harapkanNOT IN
berfungsi (yang, tidak).Perlu diketahui juga bahwa NOT IN tidak setara dengan NOT EXISTS ketika datang ke null.
Posting ini menjelaskannya dengan sangat baik
http://sqlinthewild.co.za/index.php/2010/02/18/not-exists-vs-not-in/
sumber
Jika perencana eksekusi mengatakan mereka sama, mereka sama. Gunakan mana saja yang akan membuat niat Anda lebih jelas - dalam hal ini, yang kedua.
sumber
Sebenarnya, saya percaya ini akan menjadi yang tercepat:
sumber
Saya memiliki tabel yang memiliki sekitar 120.000 catatan dan harus memilih hanya yang tidak ada (cocok dengan kolom varchar) di empat tabel lainnya dengan jumlah baris sekitar 1500, 4000, 40000, 200. Semua tabel yang terlibat memiliki indeks unik di
Varchar
kolom yang bersangkutan .NOT IN
butuh sekitar 10 menit,NOT EXISTS
butuh 4 detik.Saya memiliki kueri rekursif yang mungkin memiliki beberapa bagian tanpa tanda yang mungkin telah berkontribusi pada 10 menit, tetapi opsi lain mengambil 4 detik menjelaskan,
NOT EXISTS
setidaknya bagi saya itu jauh lebih baik atau setidaknya ituIN
danEXISTS
tidak persis sama dan selalu bernilai periksa sebelum melanjutkan dengan kode.sumber
Dalam contoh spesifik Anda, keduanya sama, karena pengoptimal telah mengetahui apa yang Anda coba lakukan adalah sama pada kedua contoh. Tetapi ada kemungkinan bahwa dalam contoh non-sepele pengoptimal mungkin tidak melakukan ini, dan dalam hal ini ada alasan untuk lebih memilih satu dari yang lain pada kesempatan.
NOT IN
harus lebih disukai jika Anda menguji beberapa baris dalam pemilihan luar Anda. Subquery di dalamNOT IN
pernyataan dapat dievaluasi pada awal eksekusi, dan tabel sementara dapat diperiksa terhadap masing-masing nilai dalam pemilihan luar, daripada menjalankan kembali subselect setiap kali seperti yang diperlukan denganNOT EXISTS
pernyataan.Jika subquery harus dikorelasikan dengan pemilihan luar, maka
NOT EXISTS
mungkin lebih disukai, karena pengoptimal dapat menemukan penyederhanaan yang mencegah pembuatan tabel sementara untuk melakukan fungsi yang sama.sumber
Saya menggunakan
dan menemukan bahwa itu memberikan hasil yang salah (Secara salah saya maksud tidak ada hasil). Karena ada NULL di TABLE2.Col1.
Saat mengubah kueri ke
memberi saya hasil yang benar.
Sejak itu saya mulai menggunakan TIDAK ADA di mana-mana.
sumber
Mereka sangat mirip tetapi tidak benar-benar sama.
Dalam hal efisiensi, saya menemukan bahwa join kiri adalah pernyataan nol yang lebih efisien (ketika banyak baris yang harus dipilih)
sumber
Jika pengoptimal mengatakan mereka sama maka pertimbangkan faktor manusia. Saya lebih suka melihat TIDAK ADA :)
sumber
Model tabel basis data
Mari kita asumsikan kita memiliki dua tabel berikut dalam database kita, yang membentuk hubungan tabel satu-ke-banyak.
The
student
tabel orangtua, danstudent_grade
adalah tabel anak karena memiliki kolom student_id Key Foreign referensi id Primary Key kolom dalam tabel mahasiswa.Ini
student table
berisi dua catatan berikut:Dan,
student_grade
meja menyimpan nilai yang diterima siswa:SQL ADA
Katakanlah kita ingin mendapatkan semua siswa yang telah menerima nilai 10 di kelas Matematika.
Jika kami hanya tertarik pada pengidentifikasi siswa, maka kami dapat menjalankan kueri seperti ini:
Tapi, aplikasi ini tertarik untuk menampilkan nama lengkap a
student
, bukan hanya pengenal, jadi kita perlu info daristudent
tabel juga.Untuk memfilter
student
catatan yang memiliki nilai 10 dalam Matematika, kita dapat menggunakan operator SQL EXIS, seperti ini:Saat menjalankan kueri di atas, kita dapat melihat bahwa hanya baris Alice yang dipilih:
Kueri luar memilih
student
kolom baris yang ingin kami kembalikan ke klien. Namun, klausa WHERE menggunakan operator EXISTS dengan subquery dalam yang terkait.Operator EXISTS mengembalikan true jika subquery mengembalikan setidaknya satu record dan false jika tidak ada baris yang dipilih. Mesin basis data tidak harus menjalankan subquery sepenuhnya. Jika satu catatan cocok, operator EXISTS mengembalikan true, dan baris kueri lainnya yang terkait dipilih.
Subquery dalam dikorelasikan karena kolom student_id dari
student_grade
tabel dicocokkan dengan kolom id dari tabel siswa luar.SQL TIDAK ADA
Mari kita pertimbangkan bahwa kita ingin memilih semua siswa yang tidak memiliki nilai lebih rendah dari 9. Untuk ini, kita dapat menggunakan TIDAK ADA, yang meniadakan logika operator EXISTS.
Oleh karena itu, operator NOT EXISTS mengembalikan true jika subquery yang mendasarinya tidak mengembalikan catatan. Namun, jika catatan tunggal dicocokkan dengan subquery batin, operator BUKAN ada akan kembali palsu, dan eksekusi subquery dapat dihentikan.
Untuk mencocokkan semua catatan siswa yang tidak memiliki tingkat student_grade terkait dengan nilai lebih rendah dari 9, kita dapat menjalankan kueri SQL berikut:
Saat menjalankan kueri di atas, kita dapat melihat bahwa hanya catatan Alice yang cocok:
Jadi, keuntungan menggunakan operator SQL EXIS dan NOT EXISTS adalah bahwa eksekusi subquery bagian dalam dapat dihentikan selama ditemukan catatan yang cocok.
sumber
Tergantung..
tidak akan relatif lambat, tidak banyak untuk membatasi ukuran dari pemeriksaan kueri untuk melihat apakah mereka kunci. Ada akan lebih disukai dalam kasus ini.
Tetapi, tergantung pada pengoptimal DBMS, ini bisa tidak berbeda.
Sebagai contoh saat EXISTS lebih baik
sumber
IN
danEXISTS
dapatkan paket yang sama di SQL Server . Pertanyaannya adalah tentangNOT IN
vsNOT EXISTS
pula.