Apakah sp_executesql dapat dikonfigurasi / digunakan secara default?

10

Saya melihat aplikasi yang menggunakan query sql yang sangat dinamis terhadap SQL Server. Melihat pertanyaan yang dibangun dengan cara yang sangat aneh dan rumit, tapi itu cerita yang berbeda, saya katakan itu untuk memberikan alasan yang baik bagi saya untuk tidak dapat (terlalu bodoh) untuk mencari tahu sendiri ... Saya tidak bisa melihat kode di mana kueri dibungkus dengan sp_executesql.

Tetapi ketika saya melacak, saya bisa melihat banyak pertanyaan datang dibungkus dengan sp_executesql. Seluruh solusi aplikasi bahkan tidak mengandung perintah sp_executesqlsama sekali.

Jadi saya bertanya-tanya apakah ada jenis konfigurasi yang saya belum tahu yang memaksa perangkat lunak untuk membungkus query dengan sp_executesql secara default?

Apa yang bisa menyebabkan perilaku ini?

Magier
sumber

Jawaban:

11

Alasan pernyataan SQL dibungkus dengan sp_executesqladalah pengaturan SqlCommand.Commandtypeproperti dan meneruskan Parameter apa pun ke perintah.

SqlCommand cmd = new SqlCommand("proc1", con);
cmd.CommandType = CommandType.StoredProcedure;                
cmd.Parameters.AddWithValue("@param1", 1);
con.Open();
cmd.ExecuteNonQuery();
con.Close();

Kode di atas berakhir dengan T-SQL ini:

exec proc1 @param1=1
SqlCommand cmd = new SqlCommand("proc1", con);
cmd.CommandType = CommandType.Text;                
cmd.Parameters.AddWithValue("@param1", 1);
con.Open();
cmd.ExecuteNonQuery();
con.Close();

Kode ini berakhir dengan eksekusi T-SQL berikut:

exec sp_executesql N'proc1',N'@param1 int',@param1=1

Penambahan 23.12.15: Menggunakan CommandType.Textperintah, hasilnya serupa: Segera setelah parameter ditambahkan ke objek perintah, .NET akan membungkus seluruh permintaan ke dalam sp_executesqldan meneruskan parameter ke sana.

Tambahan: Setelah menyelam lebih dalam sp_executesql, mengendus parameter dan merencanakan caching perilaku kelas .NET ini benar-benar masuk akal untuk menghindari kompilasi permintaan yang sering tinggi dan jumlah paket. Jadi pada dasarnya dirancang untuk memastikan kinerja SQL Server yang lebih baik secara umum sementara itu pada saat yang sama dapat menyebabkan kinerja yang buruk dari beberapa permintaan (masalah sniffing parameter) yang digunakan dengan nilai parameter yang berbeda dari rencana kueri awal yang dibuat.

Lihat:

Sampel di atas dibuat menggunakan .NET Framework 4.5 dan SQL Server 2008 Developer Edition.

Magier
sumber
5

Jika ini adalah aplikasi .NET, maka sangat mungkin hasil dari SqlCommand.ExecuteReader () dipanggil. Menurut halaman kelas SqlCommand utama , di kotak deskripsi metode di bagian "Keterangan", di bawah ExecuteReader dikatakan:

Menjalankan perintah yang mengembalikan baris. Untuk meningkatkan kinerja, ExecuteReader memanggil perintah menggunakan prosedur tersimpan sistem Transact-SQL sp_executesql . Oleh karena itu, ExecuteReader mungkin tidak memiliki efek yang Anda inginkan jika digunakan untuk menjalankan perintah seperti pernyataan SET Transact-SQL.

Saya tidak punya waktu sekarang untuk menguji ini untuk mengonfirmasi deskripsi mereka, tetapi seharusnya cukup mudah untuk membuat aplikasi konsol sederhana yang melakukan panggilan yang sangat sederhana, meneruskan beberapa teks kueri, dan termasuk parameter yang disertakan dengan a SqlParameter. Dugaan saya adalah itu ExecuteNonQuerydan ExecuteScalarjuga digunakan sp_executesqlkarena mereka juga memungkinkan untuk melewati parameter, jadi mengapa ada jalan yang berbeda untuk bagaimana mereka dieksekusi?

Solomon Rutzky
sumber