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:
Server secara otomatis cache rencana untuk digunakan kembali sebagaimana diperlukan; oleh karena itu, tidak perlu memanggil metode ini secara langsung di aplikasi klien Anda.
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 menelepon SqlCommand.Prepare()
, bahkan jika itu memanggil sp_prepexec
bukan sp_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
atau ExecuteReader
yang berikut sepenuhnya dieksekusi, dan jika itu ExecuteReader, ia mengembalikan baris. Namun, SQL Server Profiler menunjukkan bahwa SqlCommand.Execute______()
panggilan pertama setelah SqlCommand.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 dibuat sp_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:
- ** Apa yang dipersiapkan sebenarnya menyelamatkan Anda terutama waktu yang diperlukan untuk mengirimkan string kueri melalui kawat.
- Kueri yang disiapkan tidak memiliki jaminan bahwa program cache disimpan, dan tidak lebih cepat dari permintaan ad-hoc setelah mencapai server.
- RPC (CommandType.StoredProcedure) tidak mendapatkan apa-apa dari persiapan.
- Di server, pegangan yang disiapkan pada dasarnya adalah indeks ke dalam peta di dalam memori yang berisi TSQL untuk dieksekusi.
- Peta disimpan pada basis per koneksi, tidak ada penggunaan cross-connection yang memungkinkan.
- Reset dikirim ketika klien menggunakan kembali koneksi dari pool membersihkan peta.
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:
- satu-satunya manfaat nyata dari panggilan
SqlCommand.Prepare()
tampaknya adalah Anda tidak perlu mengirim teks permintaan lagi melalui jaringan,
- memanggil
sp_prepare
dan sp_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 ;-).