Saya punya pertanyaan di bawah ini:
select databasename
from somedb.dbo.bigtable l where databasename ='someval' and source <>'kt'
and not exists(select 1 from dbo.smalltable c where c.source=l.source)
Kueri di atas selesai dalam tiga detik.
Jika kueri di atas mengembalikan nilai apa pun, kami ingin prosedur tersimpan EXIT, jadi saya menulis ulang seperti di bawah ini:
If Exists(
select databasename
from somedb.dbo.bigtable l where databasename ='someval' and source <>'kt'
and not exists(select 1 from dbo.smalltable c where c.source=l.source)
)
Begin
Raiserror('Source missing',16,1)
Return
End
Namun ini membutuhkan waktu 10 menit.
Saya dapat menulis ulang kueri di atas seperti di bawah ini, yang juga selesai dalam waktu kurang dari 3 detik:
select databasename
from somedb.dbo.bigtable l where databasename ='someval' and source <>'kt'
and not exists(select 1 from dbo.smalltable c where c.source=l.source
if @@rowcount >0
Begin
Raiserror('Source missing',16,1)
Return
End
Masalah dengan penulisan ulang di atas adalah bahwa kueri di atas adalah bagian dari prosedur tersimpan yang lebih besar dan mengembalikan beberapa set hasil. Dalam C #, kita mengulangi setiap set hasil dan melakukan beberapa pemrosesan.
Di atas mengembalikan set hasil kosong, jadi jika saya pergi dengan pendekatan ini, saya harus mengubah C # dan melakukan penyebaran lagi.
Jadi pertanyaan saya adalah,
mengapa menggunakan hanya
IF EXISTS
mengubah rencana untuk mengambil begitu banyak waktu?
Di bawah ini adalah detail yang dapat membantu Anda dan beri tahu saya jika Anda membutuhkan detail:
- Buat skrip tabel dan statistik untuk mendapatkan paket yang sama dengan skrip saya
- Rencana Eksekusi Lambat
Rencana Eksekusi Cepat
Paket lambat menggunakan Brentozar Tempel paket
Cepat Rencana menggunakan Brentozar Tempel paket
Catatan: Kedua kueri itu sama (menggunakan parameter), satu-satunya perbedaan adalahEXISTS
(saya mungkin telah membuat beberapa kesalahan saat menganonimkan).
Skrip pembuatan tabel di bawah ini:
http://pastebin.com/CgSHeqXc - statistik tabel kecil
http://pastebin.com/GUu9KfpS - statistik tabel besar
sumber
Jawaban:
Seperti yang telah dijelaskan oleh Paul White dalam posting blognya: Inside the Optimizer: Row Goals In Depth ,
EXISTS
memperkenalkan tujuan baris, yang lebih disukaiNESTED LOOPS
atauMERGE JOIN
lebihHASH MATCH
Dalam kueri Anda, ini tampaknya terjadi untuk memperkenalkan loop bersarang dan menghapus paralelisme, menghasilkan rencana yang lebih lambat.
Jadi, Anda mungkin perlu menemukan cara untuk menulis ulang kueri Anda tanpa menggunakan
NOT EXISTS
dari kueri Anda.Anda mungkin lolos dengan menulis ulang kueri Anda menggunakan
LEFT OUTER JOIN
dan memeriksa tidak ada baris dalam tabel kecil dengan pengujian untukNULL
Anda mungkin dapat menggunakan
EXCEPT
kueri juga, tergantung pada berapa banyak bidang yang perlu Anda bandingkan seperti ini:Pikiran Anda, Aaron Bertrand memiliki posting blog memberikan alasan mengapa ia lebih suka TIDAK ADA yang harus Anda baca untuk melihat apakah pendekatan lain berfungsi lebih baik, dan untuk menyadari potensi masalah ketepatan jika nilai NULL.
T & J Terkait: JIKA ADA lebih lama dari pernyataan pilih tertanam
sumber
Anda perlu menulis ulang kueri Anda menggunakan gabungan eksplisit dan menentukan operasi gabungan mana yang ingin Anda gunakan (loop, hash, atau gabung) seperti ini.
Saat menggunakan EXIS atau NOT EXIS, SQL Server membuat rencana kueri dengan operasi NESTED LOOP dengan asumsi bahwa ia harus memeriksa semua baris di set satu per satu mencari baris pertama untuk memenuhi kondisi tersebut. Menggunakan HASH JOIN akan mempercepatnya.
sumber
Saya telah menemukan masalah yang sama, saya berhasil bekerja sendiri dengan menghindari menggunakan "EXISTS" dan dengan menggunakan fungsi "COUNT ()" dan pernyataan "JIKA ... LAIN".
Sebagai contoh Anda coba yang berikut ini:
Alasan saya menambahkan "+ 1" ke hitungan adalah agar saya dapat menggunakan "> 1" dalam kondisi IF, menggunakan "> 0" atau "<> 0" akan memicu kueri untuk menggunakan nested loop bukan HASH Pertandingan. Belum melihat mengapa itu persis terjadi akan menarik untuk mencari tahu mengapa.
Semoga itu bisa membantu!
sumber