Perbedaan monumental dalam waktu eksekusi antara kueri saat menggunakan petunjuk permintaan RECOMPILE

16

Saya memiliki dua kueri yang hampir sama, berjalan pada contoh SQL Server 2005 yang sama:

  1. Yang pertama adalah SELECTpermintaan asli yang dihasilkan oleh LINQ (saya tahu, saya tahu ... Saya bukan pengembang aplikasi, hanya DBA :).
  2. Yang kedua persis sama dengan yang pertama, ditambahkan OPTION (RECOMPILE)di akhir.

Tidak ada lagi yang berubah.

Yang pertama membutuhkan 55 detik setiap kali dijalankan.
Yang kedua membutuhkan waktu 2 detik.

Kedua set hasil identik.

Mengapa petunjuk ini menghasilkan keuntungan dramatis dalam kinerja?

Entri Buku Daring pada RECOMPILEtidak menawarkan penjelasan yang lebih terperinci:

Menginstruksikan Mesin Database SQL Server untuk membuang rencana yang dihasilkan untuk permintaan setelah dijalankan, memaksa pengoptimal permintaan untuk mengkompilasi ulang rencana permintaan saat berikutnya permintaan yang sama dijalankan. Tanpa menentukan RECOMPILE, Mesin Basis Data cache rencana kueri dan menggunakannya kembali. Saat menyusun rencana kueri, petunjuk kueri RECOMPILE menggunakan nilai saat ini dari variabel lokal apa pun dalam kueri dan, jika kueri berada di dalam prosedur tersimpan, nilai saat ini diteruskan ke parameter apa pun.

RECOMPILE adalah alternatif yang berguna untuk membuat prosedur tersimpan yang menggunakan klausa WITH RECOMPILE ketika hanya sebagian dari kueri di dalam prosedur tersimpan, alih-alih seluruh prosedur tersimpan, harus dikompilasi ulang. Untuk informasi lebih lanjut, lihat Mengkompilasi Ulang Prosedur yang Disimpan. RECOMPILE juga berguna saat Anda membuat panduan paket. Untuk informasi lebih lanjut, lihat Mengoptimalkan Permintaan di Aplikasi yang Disebarkan dengan Menggunakan Panduan Paket.

Karena kueri saya memiliki banyak variabel lokal, tebakan saya adalah SQL Server dapat (serius) mengoptimalkannya ketika saya menggunakan OPTION (RECOMPILE)petunjuk kueri.

Di mana-mana saya melihat orang mengatakan bahwa itu OPTION (RECOMPILE)harus dihindari. Penjelasan untuk ini secara umum adalah bahwa menggunakan petunjuk ini SQL Server tidak dapat menggunakan kembali rencana exection ini dan oleh karena itu harus membuang waktu mengkompilasi ulang setiap kali.
(Tapi) Mengingat keunggulan kinerja yang sangat besar, saya cenderung berpikir bahwa menggunakan petunjuk permintaan ini kali ini akan menjadi hal yang baik.

Haruskah saya menggunakannya? Jika tidak, adakah cara saya bisa memaksa SQL Server untuk menggunakan rencana eksekusi yang lebih baik tanpa petunjuk ini dan tanpa mengubah aplikasi?

ivanmp
sumber

Jawaban:

16

Seperti yang didokumentasikan dalam artikel Statistik yang Digunakan oleh Pengoptimal Kueri di Microsoft SQL Server 2005

Jika Anda menggunakan variabel lokal dalam predikat kueri alih-alih parameter atau literal, pengoptimal menggunakan taksiran kualitas yang lebih rendah, atau tebakan untuk selektivitas predikat. Gunakan parameter atau literal dalam kueri alih-alih variabel lokal

Ketika pengoptimal tidak memiliki statistik yang dapat digunakan sama sekali untuk sebuah kolom, maka akan menebak bahwa suatu =predikat akan cocok dengan 10% dari baris, BETWEEN9%, dan salah satu dari itu >, >=, < and <=akan cocok dengan 30%. Jika ada statistik kolom yang tersedia, =predikat akan diperlakukan berbeda seperti di bawah ini.

Bahkan ketika variabel lokal digunakan dalam kueri, perkiraan yang lebih baik daripada dugaan digunakan dalam kasus predikat kesetaraan. Selektivitas untuk kondisi bentuk " @local_variable = column_name" diperkirakan menggunakan frekuensi nilai rata-rata dari histogram untuk nama_kolom. Jadi, misalnya, jika nama kolom kolom berisi semua nilai unik, maka perkiraan selektivitas 1/(number of unique values in column)akan digunakan, yang akurat.

Jadi ini pada dasarnya sama dengan menggunakan untuk OPTIMIZE FOR (UNKNOWN). Mungkin lebih akurat daripada 10%tebakan datar, tetapi itu tidak dirancang untuk nilai spesifik yang Anda tanyakan.

Untuk memaksa SQL Server mengoptimalkan kueri setiap kali dijalankan, dan menggunakan nilai variabel lokal untuk memperkirakan kardinalitas dan biaya selama optimisasi kueri, tambahkan RECOMPILEpetunjuk kueri ke kueri.

Dengan penggunaan RECOMPILEAnda mungkin mendapatkan perkiraan kardinalitas yang lebih akurat dan oleh karena itu rencana berbeda dengan pesanan gabungan / jenis bergabung lebih cocok dengan jumlah baris yang dikembalikan dari berbagai bagian permintaan aktual Anda.

Martin Smith
sumber