Yang ini query 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:
SELECT ProductID, ProductName
FROM Northwind..Products p
WHERE p.ProductID NOT IN (
SELECT ProductID
FROM Northwind..[Order Details])
Rencana eksekusi query mengatakan mereka berdua melakukan hal yang sama. Jika itu terjadi, yang dianjurkan adalah bentuk?
Hal ini didasarkan pada database NorthWind.
[Sunting / sunting sumber]
Baru saja menemukan artikel ini bermanfaat: http://weblogs.sqlteam.com/mladenp/archive/2007/05/18/60210.aspx
Saya pikir saya'll tetap dengan TIDAK ADA.
Saya selalu default untuk TIDAK ADA
.
Rencana eksekusi mungkin sama pada saat ini tetapi jika salah satu kolom diubah di masa depan untuk memungkinkan NULL adalah
TIDAKversi akan perlu untuk melakukan lebih banyak pekerjaan (bahkan jika tidak ada
NULL yang benar-benar hadir dalam data) dan semantik TIDAK
jika `NULL ini adalah sekarang mungkin untuk menjadi orang-orang yang anda inginkan pula.
Ketika tidak Produk.ProductID
atau [Order Details].ProductID
memungkinkan NULL adalah
TIDAK` akan diperlakukan sama dengan query berikut.
SELECT ProductID,
ProductName
FROM Products p
WHERE NOT EXISTS (SELECT *
FROM [Order Details] od
WHERE p.ProductId = od.ProductId)
Rencana yang tepat dapat bervariasi tetapi untuk saya contoh data yang saya dapatkan berikut ini.
Cukup kesalahpahaman umum tampaknya menjadi yang berkorelasi sub query selalu "buruk" dibandingkan untuk bergabung. Mereka tentu dapat ketika mereka memaksa nested loop rencana (sub query dievaluasi baris demi baris) tetapi rencana ini termasuk anti semi bergabung operator logis. Anti semi bergabung tidak dibatasi untuk nested loop tetapi dapat menggunakan hash atau gabungan (seperti dalam contoh ini) bergabung juga.
/*Not valid syntax but better reflects the plan*/
SELECT p.ProductID,
p.ProductName
FROM Products p
LEFT ANTI SEMI JOIN [Order Details] od
ON p.ProductId = od.ProductId
Jika [Order Details].ProductID
adalah NOL
-dapat query kemudian menjadi
SELECT ProductID,
ProductName
FROM Products p
WHERE NOT EXISTS (SELECT *
FROM [Order Details] od
WHERE p.ProductId = od.ProductId)
AND NOT EXISTS (SELECT *
FROM [Order Details]
WHERE ProductId IS NULL)
Alasan untuk ini adalah bahwa benar semantik jika [Order Details]
berisi NULL
`ProductId ini adalah untuk kembali tidak ada hasil. Lihat ekstra anti semi bergabung dan jumlah baris spul untuk memverifikasi ini yang ditambahkan ke rencana.
Jika Produk.ProductID
juga berubah menjadi NOL
-dapat query kemudian menjadi
SELECT ProductID,
ProductName
FROM Products p
WHERE NOT EXISTS (SELECT *
FROM [Order Details] od
WHERE p.ProductId = od.ProductId)
AND NOT EXISTS (SELECT *
FROM [Order Details]
WHERE ProductId IS NULL)
AND NOT EXISTS (SELECT *
FROM (SELECT TOP 1 *
FROM [Order Details]) S
WHERE p.ProductID IS NULL)
Alasan untuk itu adalah karena NULL
Produk.ProductId
tidak boleh dikembalikan dalam hasil kecuali jika TIDAK
sub query adalah untuk kembali tidak ada hasil sama sekali (yaitu [Order Details]
meja kosong). Di mana kasus itu harus. Dalam rencana untuk data sampel ini dilaksanakan dengan menambahkan anti semi bergabung sebagai di bawah ini.
Efek ini ditunjukkan dalam blog post yang sudah dihubungkan oleh Buckley. Dalam contoh ada jumlah logis membaca meningkat dari sekitar 400 500.000.
Selain itu fakta bahwa single NULL
dapat mengurangi jumlah baris nol membuat cardinality sangat sulit. Jika SQL Server mengasumsikan bahwa hal ini akan terjadi, tetapi pada kenyataannya tidak ada NULL
baris di data sisa rencana pelaksanaan dapat serempak lebih buruk lagi, jika ini adalah hanya bagian dari yang lebih besar query, dengan pantas nested loop menyebabkan eksekusi diulang mahal sub pohon misalnya.
Hal ini tidak hanya mungkin eksekusi rencana untuk TIDAK
pada NULL
-mampu kolom namun. Artikel ini menunjukkan satu sama lain untuk query terhadap AdventureWorks2008
database.
Untuk TIDAK
pada NOT NULL kolom
atau TIDAK ADA
terhadap baik nullable atau non nullable kolom ini memberikan rencana berikut.
Ketika kolom perubahan NULL
mampu TIDAK DALAM
rencana sekarang terlihat seperti
Ia menambahkan tambahan inner join operator untuk rencana tersebut. Alat ini adalah dijelaskan di sini. Itu semua ada untuk mengkonversi single sebelumnya berkorelasi index mencari di Penjualan.SalesOrderDetail.ProductID = <correlated_product_id>
dua berusaha per outer-turut. Tambahan satu adalah di MANA Penjualan.SalesOrderDetail.ProductID NULL
.
Karena ini adalah di bawah anti semi bergabung jika yang satu kembali setiap baris kedua berusaha tidak akan terjadi. Namun jika Penjualan.SalesOrderDetail
tidak berisi NULL
`ProductID itu akan melipatgandakan jumlah mengupayakan operasi yang diperlukan.
Juga diketahui bahwa TIDAK tidak sama dengan TIDAK ADA ketika datang ke null.
Posting ini menjelaskan dengan sangat baik
http://sqlinthewild.co.za/index.php/2010/02/18/not-exists-vs-not-in/
Ketika subquery kembali bahkan salah satu null, TIDAK tidak akan cocok apapun baris.
alasan untuk ini dapat ditemukan dengan melihat rincian dari apa TIDAK beroperasi benar-benar berarti.
katakanlah, untuk tujuan ilustrasi bahwa ada 4 baris dalam tabel yang disebut t, ada kolom ID dengan nilai 1..4
di MANA SomeValue TIDAK DI (PILIH AVal DARI t)
setara dengan
di MANA SomeValue != (PILIH AVal DARI t WHERE ID=1) DAN SomeValue != (PILIH AVal DARI t WHERE ID=2) DAN SomeValue != (PILIH AVal DARI t DIMANA ID=3) DAN SomeValue != (PILIH AVal DARI t DIMANA ID=4)
Mari kita lanjut mengatakan bahwa AVal NULL where ID = 4. Oleh karena itu != perbandingan pengembalian yang tidak DIKETAHUI. Logis tabel kebenaran untuk DAN serikat yang tidak DIKETAHUI dan yang BENAR adalah tidak DIKETAHUI, tidak DIKETAHUI dan palsu adalah PALSU. Ada tidak ada nilai yang dapat DAN akan dengan tidak DIKETAHUI untuk menghasilkan hasil yang BENAR
oleh Karena itu, jika ada baris yang subquery mengembalikan NULL, seluruh TIDAK DI operator akan mengevaluasi dengan baik FALSE atau NULL dan tidak ada catatan yang akan kembali
Saya memiliki sebuah tabel yang memiliki sekitar 120.000 catatan dan perlu untuk hanya memilih orang-orang yang tidak ada (sesuai dengan kolom varchar) di empat lainnya tabel dengan jumlah baris yang kira-kira 1500, 4000, 40000, 200. Semua yang terlibat tabel memiliki indeks unik pada yang bersangkutan Varchar kolom
.
TIDAK
butuh waktu sekitar 10 menit, TIDAK ADA
mengambil 4 detik.
Saya memiliki recursive query yang mungkin memiliki beberapa yg tak disetel bagian yang mungkin telah berkontribusi terhadap 10 menit, tapi pilihan lain mengambil 4 detik menjelaskan, setidaknya untuk saya yang TIDAK ADA
adalah jauh lebih baik atau setidaknya yang DALAM
dan ADA
tidak persis sama dan selalu layak cek sebelum pergi ke depan dengan kode.
Dalam contoh spesifik mereka adalah sama, karena optimizer telah tahu apa yang anda coba lakukan adalah sama dalam kedua contoh itu. Tetapi adalah mungkin bahwa di non-sepele contoh optimizer tidak dapat melakukan hal ini, dan dalam hal itu ada alasan-alasan untuk memilih salah satu untuk lain kesempatan.
TIDAK
harus menjadi pilihan jika anda sedang menguji beberapa baris di luar anda pilih. Subquery dalam TIDAK
pernyataan yang dapat dievaluasi pada awal pelaksanaan, dan tabel sementara dapat diperiksa terhadap masing-masing nilai di luar pilih, daripada kembali menjalankan perintah subselect setiap waktu akan diperlukan dengan TIDAK ADA
pernyataan.
Jika subquery must dapat dikorelasikan dengan outer pilih, maka TIDAK ADA
mungkin lebih baik, karena optimizer dapat menemukan sebuah penyederhanaan yang mencegah penciptaan setiap tabel sementara untuk melakukan fungsi yang sama.
Saya menggunakan
SELECT * from TABLE1 WHERE Col1 NOT IN (SELECT Col1 FROM TABLE2)
dan menemukan bahwa itu memberikan hasil yang salah (Oleh salah saya berarti tidak ada hasil). Seperti ada yang NULL di TABLE2.Col1.
Sementara mengubah query untuk
SELECT * from TABLE1 T1 WHERE NOT EXISTS (SELECT Col1 FROM TABLE2 T2 WHERE T1.Col1 = T2.Col2)
memberi saya hasil yang benar.
Sejak itu saya sudah mulai menggunakan TIDAK ADA di mana-mana.
Hal ini tergantung..
SELECT x.col
FROM big_table x
WHERE x.key IN( SELECT key FROM really_big_table );
tidak akan relatif lambat isn't banyak untuk membatasi ukuran apa query periksa untuk melihat jika mereka adalah kunci dalam. ADA akan lebih baik dalam kasus ini.
Tapi, tergantung pada DBMS's optimizer, ini bisa menjadi tidak berbeda.
Sebagai contoh ketika ADA lebih baik
SELECT x.col
FROM big_table x
WHERE EXISTS( SELECT key FROM really_big_table WHERE key = x.key);
AND id = very_limiting_criteria