Kapan sp_executesql menyegarkan paket permintaan?

13

Anda harus memaafkan kenaifan saya karena saya bukan DBA tetapi pemahaman saya adalah bahwa seiring waktu statistik dari perubahan database dan prosedur yang disimpan harus dikompilasi ulang untuk menjaga rencana kueri tetap up to date dengan statistik terbaru.

Dengan asumsi saya memiliki prosedur tersimpan dalam database saya yang dikompilasi ulang terhadap statistik terbaru pada beberapa interval reguler, apa implikasi dari menyelaraskan prosedur tersimpan dalam kode dan membungkusnya dalam sebuah sp_executesqlpernyataan? Apakah saya kehilangan penyegaran dari rencana kueri yang dulu terjadi sebagai bagian dari kompilasi ulang prosedur?

Jika ada hal lain (selain izin) yang perlu saya pertimbangkan sebelum saya melakukan perubahan ini maka saya akan menghargai wawasan Anda.

Saya membaca ini di MSDN:

Kemampuan pengoptimal permintaan SQL Server untuk mencocokkan string Transact-SQL baru dengan rencana eksekusi yang ada terhambat oleh nilai parameter yang terus berubah dalam teks string, terutama dalam pernyataan Transact-SQL yang kompleks.

Jadi dengan asumsi prosedur tersimpan yang saya coba in-line dan bungkus sp_executesqlmemang mengandung beberapa parameter, apakah ini mengatakan bahwa meskipun rencana eksekusi saya di-cache, saya mempersulit SQL Server untuk menemukan dan menggunakannya kembali?

james lewis
sumber

Jawaban:

7

Baris dari MSDN sedang berbicara tentang penggunaan EXEC(), seperti ini:

SET @sql = 'SELECT foo FROM dbo.bar WHERE x = ''' + @x + ''';';
EXEC(@sql);

Dalam pengujian saya, versi modern SQL Server masih dapat menggunakan kembali rencana seperti ini, tetapi mungkin ada variabel lain (seperti versi, atau misalnya jika Anda menambahkan WHEREklausa kondisional berdasarkan keberadaan parameter tertentu - dalam hal ini akan menghasilkan rencana yang berbeda).

Jika Anda menggunakan sp_executesqlmaka nilai-nilai parameter masih dapat menyebabkan masalah sniffing parameter (seperti halnya dengan SQL normal), tetapi ini tidak ada hubungannya dengan apakah SQL Server dapat menggunakan kembali paket. Paket ini akan digunakan berulang-ulang, sama seperti jika Anda tidak menggunakan sp_executesqlsama sekali, kecuali variabel yang akan menyebabkan kueri langsung untuk dikompilasi ulang, dalam hal ini yang ini akan dikompilasi ulang juga (pada dasarnya, SQL Server tidak menyimpan apa pun dengan rencana yang mengatakan "ini dieksekusi dari sp_executesql, tetapi yang ini tidak):

SET @sql = N'SELECT foo FROM dbo.bar WHERE x = @x;';
EXEC sp_executesql @sql, N'@x VARCHAR(32)', @x;

Sebagai bonus, ini memiliki perlindungan bawaan terhadap SQL dinamis dan menghindari Anda harus khawatir melipatgandakan tanda kutip tunggal karena pembatas string. Saya membuat blog tentang ini di sini .

Jika Anda mengalami masalah dengan rencana penggunaan kembali dan / atau parameter mengendus, beberapa hal yang Anda harus melihat ke yang OPTION (RECOMPILE), OPTIMIZE FOR, optimize for ad hoc workloadsdan simple/forced parameterization. Saya menjawab beberapa pertanyaan serupa sebagai tanggapan terhadap siaran web baru-baru ini di sini, mungkin ini sepele:

http://sqlperformance.com/performance-palooza

Intinya adalah: jangan takut untuk menggunakannya sp_executesql, tetapi hanya menggunakannya saat Anda membutuhkannya, dan hanya menghabiskan energi yang terlalu optimal ketika Anda memiliki masalah kinerja yang sebenarnya. Contoh di atas adalah yang mengerikan karena tidak ada alasan untuk menggunakan SQL dinamis di sini - Saya telah menulis jawaban ini dengan asumsi Anda memiliki use case yang sah.

Aaron Bertrand
sumber
2

Kueri yang dijalankan melalui sp_executesql mengikuti aturan yang sama dari rencana eksekusi seperti kueri normal yang tidak dijalankan melalui sp_executesql. Jika teks kueri berubah maka rencana baru dibuat. Jika teks tidak berubah karena pengguna parameter maka paket tersebut digunakan kembali. Ketika statistik diperbarui maka paket kedaluwarsa dan rencana baru dihasilkan pada saat berikutnya kueri dijalankan.

mrdenny
sumber
Terima kasih atas jawaban Anda, saya membuat edit mengenai parameter karena sekarang saya menyadari bahwa setiap kali saya menelepon sp_ExecuteSql, saya akan menggunakan string yang berbeda sebagai kueri karena fakta bahwa, dari perspektif Sql Server, saya telah mengganti parameter dengan nilai-nilai kode keras (mereka akan dimasukkan dalam kode sebelum saya mengirim permintaan saya ke Sql Server). Apakah Anda tahu jalan keluarnya? Apakah mendeklarasikan variabel dalam pernyataan sql sebaris saya membantu pengoptimal kueri untuk menemukan paket kueri yang di-cache
james lewis