Tiba-tiba Rencana Eksekusi Lambat untuk Proc Tersimpan

15

Saya mencoba memahami masalah yang kami alami dengan SQL Server 2000. Kami adalah situs web yang cukup transaksional dan kami memiliki proc tersimpan sp_GetCurrentTransactionsyang menerima customerID, dan dua tanggal.

Sekarang tergantung pada tanggal, dan pelanggan, permintaan ini dapat mengembalikan apa pun dari nol hingga 1000-an baris.

Masalahnya: apa yang kami alami adalah bahwa tiba-tiba kami akan mendapatkan sejumlah kesalahan (biasanya Execution Timeout Expiredatau serupa) untuk klien tertentu ketika mereka mencoba menjalankan proc yang disimpan. Jadi kami memeriksa kueri, menjalankannya dalam SSMS dan dan menemukan bahwa dibutuhkan 30-an. Jadi kami mengkompilasi ulang proc yang tersimpan dan -bang- sekarang berjalan dalam 300ms.

Saya sudah bicara dengan DBA kami tentang ini. Dia telah memberi tahu saya bahwa database membuat rencana kueri ketika kami membuat proc yang disimpan. Dia mengatakan bahwa itu adalah rencana yang bagus untuk set parameter itu, tetapi jika Anda melempar set parameter tertentu padanya, maka rencana itu tidak akan menjadi rencana terbaik untuk data itu, sehingga Anda akan melihatnya berjalan lambat.

Opsi yang disajikan kepada saya adalah langkah yang kueri masalah dari proc yang disimpan dan kembali ke SQL dinamis yang memiliki rencana eksekusi yang dibuat pada setiap proses.

Ini terasa seperti langkah mundur bagi saya dan saya merasa harus ada jalan keluar untuk hal ini. Apakah ada cara lain untuk mengatasi masalah ini?

Setiap dan semua tanggapan dihargai.

Ciaran Archer
sumber
apakah ada pernyataan if / else di proc? Saya telah melihat ini terjadi ketika rencana itu di-cache dalam pernyataan if dan kemudian mencoba mengeksekusi di bawah blok lain menggunakan rencana yang salah. Apakah kesalahan ini sesuai dengan perubahan dalam proc?
Jeremy Grey
@Jeremy: Tidak ada perubahan pada proc dan tidak ada yang lain / jika pernyataan.
Ciaran Archer

Jawaban:

14

Masalah ini disebut sniffing parameter.

Versi SQL Server yang lebih baru memberi Anda lebih banyak opsi untuk mengatasinya seperti OPTION (RECOMPILE)atau OPTIMIZE FORpetunjuk.

Anda dapat mencoba mendeklarasikan variabel dalam prosedur tersimpan, menetapkan nilai parameter ke variabel dan menggunakan variabel di tempat parameter karena kedengarannya seolah-olah sebagian besar waktu Anda mendapatkan paket yang cukup memuaskan.

Biasanya rencana yang paling buruk adalah dikompilasi untuk parameter dengan selektivitas sangat tinggi tetapi dijalankan dengan parameter dengan selektivitas rendah.

Dengan asumsi rencana yang dihasilkan lebih kuat dengan pendekatan ini dan memuaskan untuk semua nilai parameter maka keuntungan dari pendekatan ini dibandingkan yang disarankan oleh JNK adalah bahwa hal itu tidak menimbulkan biaya kompilasi untuk setiap panggilan.

Kerugiannya adalah bahwa untuk beberapa eksekusi, waktu berjalan mungkin lebih besar daripada untuk sebuah rencana yang dirancang khusus untuk nilai parameter tersebut sehingga merupakan trade off dari waktu kompilasi vs waktu eksekusi.

Martin Smith
sumber
3
Atau "bind mengintip" dalam terminologi Oracle
Gayus
Terima kasih @ Gayus, baik untuk mengetahui terminologi untuk lebih dari satu RDBMS;)
Andrei Rînea
6

Alih-alih menggunakan SQL dinamis, Anda selalu bisa mengubah panggilan proc ke:

EXEC Database.dbo.usp_Myprocedure 'Parameter' WITH RECOMPILE

The WITH RECOMPILEkekuatan (Anda dapat menebaknya!) Mengkompilasi ulang rencana eksekusi setiap kali dijalankan.

Anda juga dapat memasukkan WITH RECOMPILEdalam definisi proc yang disimpan:

CREATE PROCEDURE usp.MyProcedure (Parameters)
WITH RECOMPILE
AS
...
JNK
sumber
2

Anda juga dapat mencoba memutuskan untuk basis data yang akan digunakan, meskipun Anda akan sedikit berkelahi dengan pengoptimal, sehingga lebih rapuh daripada yang Anda harapkan.

Tekniknya adalah ini - pecahkan prosedur yang tersimpan menjadi 2, satu dimaksudkan untuk satu set parameter, satu untuk yang lain. Tambahkan klausa mana ke masing-masing sehingga di antara mereka mereka mencakup semua kasus yang mungkin. Lihatlah paket kueri - satu harus dioptimalkan untuk satu set parameter, yang lain untuk set lainnya. Anda mungkin harus mengutak-atik kueri agar hal ini terjadi, atau ini mungkin tidak mungkin dicapai untuk kueri Anda, dalam hal ini pendekatan ini tidak akan berfungsi.

Sekarang buat prosedur tersimpan asli Anda periksa nilai parameter dan kirim ke salah satu dari dua prosedur yang tersimpan dari paragraf sebelumnya.

Ini bisa berhasil, tapi ini semacam peretasan untuk memaksa pengoptimal bekerja lebih efektif untuk kueri Anda. Seperti semua peretasan seperti itu, dalam versi basis data yang akan datang mungkin tidak perlu atau bahkan memperburuk keadaan. Jadi, bahkan jika itu berhasil, Anda harus memutuskan apakah itu layak.

psr
sumber
1

Anda juga dapat mencoba SET FORCEPLANdan mengindeks petunjuk.

http://msdn.microsoft.com/en-us/library/ms188344.aspx
Ini pada dasarnya memungkinkan Anda untuk memilih urutan pesanan yang terjadi.

Anda dapat memiliki petunjuk indeks untuk memastikan bahwa server SQL menggunakan indeks yang benar.

pengguna606723
sumber
0

Hmmm ... jika kita fokus hanya pada prosedur tersimpan yang satu ini, saya akan terkejut bahwa menggunakan rencana eksekusi yang di-cache akan menyebabkan masalah yang Anda lihat. Saya akan meminta untuk melihat rencana pelaksanaan prosedur tersimpan menggunakan seperangkat parameter untuk pelanggan dan dua tanggal. Saya ingin tahu apakah indeks yang lebih spesifik akan membantu -> seperti pada customerId, dan hanya dua tanggal?

Brian Knight
sumber
2
Kenapa terkejut? parameter sniffing adalah masalah yang cukup umum dengan gejala-gejala ini dan sepertinya DBA telah mengidentifikasi itu sebagai masalah.
Martin Smith
@ MartinSmith - Saya sedikit terkejut bahwa DBA yang tahu tentang sniffing paramter tidak tahu tentang petunjuk kompilasi ...
JNK
@ JNK - Itu benar. Tidak yakin mengapa mereka tidak menyebutkan itu.
Martin Smith
0

Tiba-tiba menurunkan kinerja terdengar seperti rencana kueri yang tidak efisien yang dihasilkan, mungkin karena statistik yang hilang. Jalankan profiler SQL Server dengan kategori acara "Kesalahan dan Peringatan" yang ditetapkan dan lihat apakah ada peringatan tentang statistik yang hilang.

Anda mungkin juga kehilangan indeks, atau Anda mungkin perlu men-defrag indeks karena mereka mungkin terlalu terfragmentasi untuk SQL Server untuk digunakan, sehingga berpikir bahwa Pemindaian Tabel akan menghasilkan lebih sedikit I / O.

@JNK memunculkan poin yang bagus tentang procs yang disimpan - ini dikompilasi dimuka dan rencana kueri akan disimpan bersama dengan prosedur yang tersimpan.

Saya tidak serta merta setuju dengan penggunaan DENGAN RECOMPILE karena Anda kemudian kehilangan manfaat dari rencana kueri yang disimpan dan digunakan kembali. Ada beberapa kasus saat ini diperlukan - yaitu jika statistik distribusi Anda di tabel yang mendasari sangat berbeda antara panggilan, tetapi secara umum, setelah data dalam tabel matang, distribusi data di dalam tabel akan bervariasi minimal.

Jadi, untuk meringkas:

  1. Periksa statistik yang hilang
  2. Periksa fragmentasi indeks
  3. Buat dan gunakan proc yang tersimpan
  4. Silakan ganti nama proc - sp_ adalah namespace awalan yang disediakan untuk sistem internal SQL Server procs - yang mengakibatkan SQL Server selalu mencari dalam database master untuk prosedur tersimpan yang pertama. Mengganti nama proc usp_ alih-alih sp_ akan menghasilkan peningkatan kinerja, tapi saya ragu ini masalah Anda dalam kasus ini.
ifx
sumber