Adakah yang tahu mengapa itu IF EXISTS
akan membuatnya berjalan lebih lama dan melakukan lebih banyak bacaan? Saya juga mengubah pernyataan pilih untuk dilakukan SELECT TOP 1 [dlc].[id]
dan saya membunuhnya setelah 2 menit.
Seperti yang saya jelaskan dalam jawaban saya untuk pertanyaan terkait ini:
Bagaimana (dan mengapa) TOP mempengaruhi rencana eksekusi?
Menggunakan EXISTS
memperkenalkan tujuan baris, di mana pengoptimal menghasilkan rencana eksekusi yang bertujuan untuk menemukan baris pertama dengan cepat. Dalam melakukan ini, diasumsikan bahwa data terdistribusi secara seragam. Misalnya, jika statistik menunjukkan ada 100 pertandingan yang diharapkan dalam 100.000 baris, itu akan menganggap itu harus membaca hanya 1.000 baris untuk menemukan pertandingan pertama.
Ini akan menghasilkan waktu eksekusi yang lebih lama dari yang diharapkan jika asumsi ini ternyata salah. Misalnya, jika SQL Server memilih metode akses (mis. Pemindaian tidak berurutan) yang terjadi untuk menemukan nilai pencocokan pertama sangat terlambat dalam pencarian, itu bisa menghasilkan pemindaian yang hampir lengkap. Di sisi lain, jika baris yang cocok ditemukan di antara beberapa baris pertama, kinerja akan sangat baik. Ini adalah risiko mendasar dengan sasaran baris - kinerja yang tidak konsisten.
Sebagai perbaikan sementara, saya telah mengubahnya untuk melakukan penghitungan (*) dan menetapkan nilai itu ke variabel
Biasanya dimungkinkan untuk merumuskan ulang kueri sedemikian rupa sehingga sasaran baris tidak ditetapkan. Tanpa sasaran baris, kueri masih dapat berakhir ketika baris pertama yang cocok ditemukan (jika ditulis dengan benar), tetapi strategi rencana eksekusi kemungkinan akan berbeda (dan mudah-mudahan, lebih efektif). Jelas, hitung (*) akan membutuhkan membaca semua baris, jadi itu bukan alternatif yang sempurna.
Jika Anda menjalankan SQL Server 2008 R2 atau yang lebih baru, Anda juga dapat secara umum menggunakan flag jejak yang didokumentasikan dan didukung 4138 untuk mendapatkan rencana eksekusi tanpa sasaran baris. Bendera ini juga dapat ditentukan menggunakan petunjuk yang didukung OPTION (QUERYTRACEON 4138)
, meskipun perlu diketahui bahwa ini memerlukan izin sysadmin runtime , kecuali digunakan dengan panduan paket.
Sayangnya
Tidak satu pun di atas yang berfungsi dengan IF EXISTS
pernyataan bersyarat. Ini hanya berlaku untuk DML biasa. Ini akan bekerja dengan SELECT TOP (1)
formulasi alternatif yang Anda coba. Itu mungkin lebih baik daripada menggunakan COUNT(*)
, yang harus menghitung semua baris yang memenuhi syarat, seperti yang disebutkan sebelumnya.
Yang mengatakan, ada sejumlah cara untuk mengekspresikan persyaratan ini yang akan memungkinkan Anda untuk menghindari atau mengendalikan tujuan baris, sambil menghentikan pencarian lebih awal. Satu contoh terakhir:
DECLARE @Exists bit;
SELECT @Exists =
CASE
WHEN EXISTS
(
SELECT [dlc].[ID]
FROM TableDLC [dlc]
JOIN TableD [d]
ON [d].[ID] = [dlc].[ID]
JOIN TableC [c]
ON [c].[ID] = [d].[ID2]
WHERE [c].[Name] <> [dlc].[Name]
)
THEN CONVERT(bit, 1)
ELSE CONVERT(bit, 0)
END
OPTION (QUERYTRACEON 4138);
IF @Exists = 1
BEGIN
...
END;
IF NOT EXISTS (...) BEGIN END ELSE BEGIN <do something> END
.