Kode membuat rencana berbeda ketika dijalankan ad-hoc vs. dalam prosedur tersimpan

9

Saya memiliki pernyataan penghapusan yang menggunakan paket yang buruk saat dijalankan di dalam prosedur tersimpan, tetapi memilih paket yang lebih baik ketika dijalankan secara ad-hoc.

Saya telah membangun kembali semua indeks untuk tabel yang digunakan oleh kueri dan menjatuhkan semua cache. Pengoptimal masih memilih rencana yang salah untuk prosedur tersimpan.

Saya ingin tahu mengapa pengoptimal menggunakan rencana eksekusi yang berbeda untuk prosedur tersimpan versus ad-hoc SQL.

UPDATE: Saya kira itu pasti parameter setelah semua- ketika saya menjalankan kode ad-hoc dengan variabel hardcoded, saya bisa mendapatkan paket "buruk" dengan nilai yang benar (ini adalah tanggal, nilai yang berumur satu tahun tampaknya menghasilkan rencana "baik"). Sekarang untuk mencoba memaksa rencana "baik" pada proc dengan menggunakan petunjuk kueri.

SOLUSI: Saya akhirnya mendapatkan rencana yang saya inginkan dengan menggunakan petunjuk MENGOPTIMALKAN UNTUK TIDAK DIKENAL.

msgisme
sumber
Mungkin mengendus parameter . Apakah kueri merujuk variabel dalam WHEREklausa?
Nick Chammas
4
Bisakah Anda menambahkan kode
gbn
Tolong juga posting rencana di suatu tempat. Seperti, akan sangat sulit untuk memberi tahu Anda secara persis mengapa rencananya berbeda.
Aaron Bertrand
OK, informasi lebih lanjut: Saya tidak dapat memposting rencana dan kode sampai saya mengaburkannya sedikit. Saya akan mencoba untuk membuatnya dalam beberapa. Rencana untuk prosedur tersimpan (buruk) melakukan pemindaian indeks berkerumun dari tabel besar (semuanya, semua partisi). Kemudian menggunakan loop untuk menemukan baris dari tabel yang lebih kecil, dan kemudian menghapus dari tabel yang lebih kecil.
msgisme
Rencana untuk kode ad-hoc (baik) melakukan pemindaian tabel pada tabel kecil (yang hanya memiliki 5-10 baris) dan menggunakan indeks non-clustered dari tabel besar untuk menemukan baris mana yang perlu diperiksa di PK dari meja besar. Saya akan mencoba untuk mendapatkan rencana yang sebenarnya secepat mungkin.
msgisme

Jawaban:

5

Tersangka biasa:

  1. konstanta dalam adhoc, parameter dalam kode
  2. ketidakcocokan tipe data dalam kode
  3. parameter mengendus

Butir 1: pengoptimal dapat memilih rencana terbaik untuk konstanta.
Ubah konstanta = ubah rencana. Plen parametrised dapat direset

Poin 2 akan memperkenalkan konversi implisit karena prioritas datatype
misalnya kolom varchar dibandingkan dengan parameter nvarchar

Butir 3: gunakan parameter masking atau OPTIMASI UNTUK TIDAK DIKETAHUI
Edit: Untuk menguji: jalankan proc tersimpan, jalankan sp_updatestats, jalankan lagi. Ini akan membatalkan paket cache yang lebih baik daripada menghapus cache paket

Sunting: setelah komentar jcolebrand

Anda dapat menonaktifkan beberapa cara. 3 utama adalah

  • RECOMPILE. Ini IMO konyol.
  • MENGOPTIMALKAN (sic) UNTUK DIKETAHUI
  • Parameter masking

Parameter masking:

DECLARE @MaskedParam varchar(10)
SELECT @MaskedParam = @SignaureParam

SELECT...WHERE column = @MaskedParam

Masking dan petunjuk OPTIMIZE memiliki efek yang sama (mungkin karena alasan yang berbeda). Artinya, pengoptimal harus menggunakan statistik dan distribusi data ( Catatan: masih dalam pengujian oleh Mark Storey-Smith ) mengevaluasi parameter pada kemampuan mereka sendiri ? , daripada apa panggilan terakhir mereka. Pengoptimal dapat mengkompilasi ulang atau tidak. SQL Server 2005 menambahkan kompilasi tingkat pernyataan sehingga dampaknya lebih kecil

Sekarang, mengapa rencana dengan parameter "mengendus" adalah "lengket" dibandingkan dengan parameter bertopeng / "tidak diketahui", saya tidak yakin.

Saya telah menggunakan parameter masking sejak SQL Server 2000 untuk semua kecuali kode paling sederhana. Saya telah mencatat bahwa itu mungkin terjadi dengan kode yang lebih kompleks. Dan di pekerjaan lama saya, saya memiliki beberapa procs laporan bahwa saya dapat mengubah default parameter paket. Saya rasa pendekatan "pemujaan kargo" lebih mudah daripada panggilan dukungan.

Edit 2, 12 Okt 2011, setelah mengobrol

  • Parameter masking dan MENGOPTIMALKAN UNTUK TIDAK DIKETAHUI memiliki efek yang sama sejauh yang saya tahu
    . Petunjuknya lebih bersih daripada masking tetapi ditambahkan dengan SQL Server 2008.

  • Parameter sniffing terjadi pada waktu kompilasi.
    DENGAN RECOMPILE menghasilkan rencana baru setiap eksekusi. Ini berarti pilihan standar yang buruk akan memengaruhi rencana. Di pekerjaan terakhir saya, saya bisa mendemonstrasikan ini dengan mudah dengan beberapa kode laporan: mengubah standar parameter mengubah paket tanpa memperhatikan parameter yang disediakan.

  • Artikel MS Connect ini menarik: Penggunaan indeks suboptimal dalam prosedur tersimpan (disebutkan dalam salah satu jawaban SO di bawah)

  • Bob Beauchemin juga menyebutkannya

Masalah luar biasa

  • Apakah sniffing masih berlaku dengan WITH RECOMPILE? Yaitu, jika pengoptimal tahu untuk membuang rencana apakah itu bertujuan untuk digunakan kembali?

  • Mengapa rencana mengendus "lengket"?

Tautan dari SO:

gbn
sumber
1. Param di sp adalah variabel dalam kode 2. Sekali lagi, datatype yang sama 3. Saya telah menjalankan keduanya dengan berbagai parameter, dan saya mendapatkan rencana yang sama setiap kali. Saya membersihkan cache setelah setiap upaya.
msgisme
1
Re: point 3. Anda juga dapat menjalankan pernyataan dengan OPTION (RECOMPILE)atau seluruh proc WITH RECOMPILEuntuk memaksa SQL Server untuk mengabaikan rencana yang ada.
Nick Chammas
3
BTW itu OPTIMIZE, karena Microsoft adalah perusahaan Amerika. :)
Nick Chammas
1
@ Gbn ada pemikiran tentang mencegah / mengalahkan sniffing parameter?
jcolebrand
1
@ jcolebrand: jawaban sederhana adalah "tidak" :-)
gbn
2

Jangan lupa bahwa pengaturan ANSI yang telah Anda atur untuk rencana koneksi berperan dalam pemilihan paket eksekusi. Saat aplikasi memanggil prosedur tersimpan, mungkin pengaturan ANSI berbeda dari koneksi SSMS Anda.

mrdenny
sumber