Saya menemukan kode pengembang di mana metode SqlCommand.Prepare () (lihat MSDN) secara luas digunakan sebelum pelaksanaan query SQL. Dan saya bertanya-tanya apa manfaat dari ini?
Sampel:
command.Prepare();
command.ExecuteNonQuery();
//...
command.Parameters[0].Value = 20;
command.ExecuteNonQuery();
Saya telah bermain-main sedikit dan ditelusuri. Eksekusi Perintah setelah memanggil Prepare()
metode membuat Sql Server menjalankan pernyataan berikut:
declare @p1 int
set @p1=1
exec sp_prepexec @p1 output,N'@id int,@desc text',N'INSERT INTO dbo.testtable (id) VALUES (@id)',@id=20'
select @p1
Setelah itu ketika Parameter mendapatkan nilainya dan SqlCommand.ExecuteNonQuery()
dipanggil, berikut ini dieksekusi pada Sql-Server:
exec sp_execute 1,@id=20
Bagi saya ini sepertinya pernyataan yang dikompilasi segera Prepare()
dieksekusi. Saya bertanya-tanya apa manfaat dari ini? Apakah ini berarti bahwa itu dimasukkan ke dalam cache rencana dan dapat digunakan kembali segera setelah permintaan akhir dieksekusi dengan nilai parameter yang diinginkan?
Saya menemukan (dan mendokumentasikannya dalam pertanyaan lain ) bahwa SqlCommands yang dieksekusi dengan SqlParameters selalu dibungkus dengan sp_executesql
panggilan prosedur. Ini membuat Sql Server dapat menyimpan dan menggunakan kembali paket independen dari nilai parameter.
Mengenai hal ini saya bertanya-tanya apakah prepare()
metode ini tidak berguna atau usang atau jika saya kehilangan sesuatu di sini?
Jawaban:
Mempersiapkan batch SQL secara terpisah dari mengeksekusi batch SQL yang disiapkan adalah konstruksi yang efektif **tidak berguna untuk SQL Server mengingat bagaimana rencana eksekusi di-cache. Memisahkan langkah-langkah persiapan (parsing, mengikat parameter apa pun, dan kompilasi) dan eksekusi hanya masuk akal ketika tidak ada caching. Tujuannya adalah untuk menghemat waktu yang dihabiskan untuk parsing dan kompilasi dengan menggunakan kembali rencana yang ada, dan inilah yang dilakukan cache rencana internal. Tetapi tidak semua RDBMS melakukan level caching ini (jelas dari keberadaan fungsi-fungsi ini) sehingga diserahkan kepada kode klien untuk meminta agar suatu rencana "di-cache", dan kemudian simpan cache ID itu, kemudian gunakan kembali Itu. Ini adalah beban tambahan pada kode klien (dan programmer untuk mengingat untuk melakukannya dan melakukannya dengan benar) yang tidak perlu. Bahkan, halaman MSDN untuk metode IDbCommand.Prepare () menyatakan:
Perlu dicatat bahwa, sejauh pengujian saya menunjukkan (yang cocok dengan apa yang Anda tunjukkan dalam Pertanyaan), memanggil SqlCommand.Prepare () , tidak melakukan "persiapan" - hanya operasi: ia memanggil sp_prepexec yang menyiapkan dan mengeksekusi SQL ; itu tidak memanggil sp_prepare yang hanya parse dan kompilasi (dan tidak mengambil nilai parameter apa pun, hanya nama dan tipe data mereka). Karenanya, tidak mungkin ada manfaat "pra-kompilasi" dari panggilan
SqlCommand.Prepare
karena melakukan eksekusi langsung (dengan asumsi tujuannya adalah untuk menunda eksekusi). NAMUN , ada manfaat kecil potensial yang menarik dari meneleponSqlCommand.Prepare()
, bahkan jika itu memanggilsp_prepexec
bukansp_prepare
. Silakan lihat catatannya (** ) di bagian bawah untuk detail.Pengujian saya menunjukkan bahwa bahkan ketika
SqlCommand.Prepare()
dipanggil (dan harap dicatat bahwa panggilan ini tidak mengeluarkan perintah apa pun pada SQL Server),ExecuteNonQuery
atauExecuteReader
yang berikut sepenuhnya dieksekusi, dan jika itu ExecuteReader, ia mengembalikan baris. Namun, SQL Server Profiler menunjukkan bahwaSqlCommand.Execute______()
panggilan pertama setelahSqlCommand.Prepare()
panggilan terdaftar sebagai acara "Siapkan SQL", dan.Execute___()
panggilan berikutnya mendaftar sebagai peristiwa "Exec Prepared SQL".Kode Uji
Sudah diunggah ke PasteBin di: http://pastebin.com/Yc2Tfvup . Kode ini menciptakan .NET / C # Aplikasi Konsol yang dimaksudkan untuk berjalan saat pelacakan SQL Server Profiler sedang berjalan (atau sesi Acara yang Diperpanjang). Itu berhenti setelah setiap langkah sehingga akan menjadi jelas pernyataan mana yang memiliki efek tertentu.
MEMPERBARUI
Menemukan lebih banyak info, dan sedikit alasan potensial untuk menghindari panggilan
SqlCommand.Prepare()
. Satu hal yang saya perhatikan dalam pengujian saya, dan apa yang harus dicatat bagi siapa saja yang menjalankan aplikasi Konsol pengujian itu: tidak pernah ada panggilan eksplisit yang dibuatsp_unprepare
. Saya melakukan penggalian dan menemukan posting berikut di forum MSDN:SqlCommand - Mempersiapkan atau tidak mempersiapkan?
Jawaban yang diterima berisi banyak info, tetapi poin penting adalah:
Saya juga menemukan posting berikut dari tim SQLCAT, yang tampaknya terkait, tetapi hanya bisa menjadi masalah khusus untuk ODBC sedangkan SqlClient tidak membersihkan dengan benar setelah membuang SqlConnection. Sulit untuk mengatakan karena posting SQLCAT tidak menyebutkan tes tambahan yang akan membantu membuktikan ini sebagai penyebab, seperti membersihkan kumpulan koneksi, dll.
Perhatikan pernyataan SQL yang disiapkan itu
KESIMPULAN
Mengingat bahwa:
SqlCommand.Prepare()
tampaknya adalah Anda tidak perlu mengirim teks permintaan lagi melalui jaringan,sp_prepare
dansp_prepexec
menyimpan teks kueri sebagai bagian dari memori koneksi (yaitu memori SQL Server)Saya akan merekomendasikan untuk tidak menelepon
SqlCommand.Prepare()
karena satu-satunya manfaat potensial adalah menghemat paket jaringan sementara kekurangannya adalah mengambil lebih banyak memori server. Sementara jumlah memori yang dikonsumsi mungkin sangat kecil di sebagian besar kasus, bandwidth jaringan jarang menjadi masalah karena sebagian besar server DB terhubung langsung ke server aplikasi lebih dari 10 Megabit minimum (lebih mungkin 100 Megabit atau Gigabit hari ini) koneksi ( dan beberapa bahkan ada di kotak yang sama ;-). Itu dan memori hampir selalu merupakan sumber daya yang lebih langka daripada bandwidth jaringan.Saya kira, bagi siapa pun yang menulis perangkat lunak yang dapat terhubung ke banyak basis data, maka kenyamanan antarmuka standar dapat mengubah analisis biaya / manfaat ini. Tetapi bahkan dalam kasus itu, saya harus percaya bahwa itu masih cukup mudah untuk abstrak antarmuka DB "standar" yang memungkinkan untuk penyedia yang berbeda (dan karenanya perbedaan di antara mereka, seperti tidak perlu menelepon
Prepare()
) mengingat bahwa melakukannya adalah objek dasar Pemrograman berorientasi yang kemungkinan besar sudah Anda lakukan dalam kode aplikasi Anda ;-).sumber
sp_prepare
dalam panggilan kesp_executesql
, hanya untuk memastikan. Untuk langkah 10, ya, saya melakukan lebih banyak pengujian kemarin dan memang melihat beberapa kesempatan dengan pegangan berbeda untuksp_prepare
, tetapi masih belum pernah sama untuksp_executesql
. Saya akan menguji satu hal lagi dan memperbarui jawaban saya.sp_executesql
tidak bisa atau tidak. Tapi bagaimanapun, waktu parse masih ada di sanasp_prepare
jika rencana tersebut telah dihapus dari cache jadi saya akan menghapus bagian dari jawaban saya (menarik tetapi tidak relevan). Bagian itu lebih merupakan catatan tambahan yang menarik karena tidak membahas pertanyaan langsung Anda. Semuanya masih berlaku.Saya akan mengatakan bahwa metode Siapkan memiliki nilai SqlCommand dunia terbatas, bukan berarti itu sama sekali tidak berguna. Satu manfaat adalah bahwa Mempersiapkan adalah bagian dari antarmuka IDbCommand yang mengimplementasikan SqlCommand. Ini memungkinkan kode yang sama untuk dijalankan terhadap penyedia DBMS lainnya (yang mungkin memerlukan Siapkan) tanpa logika kondisional untuk menentukan apakah Siapkan harus dipanggil atau tidak.
Mempersiapkan tidak memiliki nilai dengan .NET Provider untuk SQL Server selain kasus penggunaan ini, AFAIK.
sumber