Saya tahu prosedur tersimpan lebih efisien melalui jalur eksekusi (daripada sql inline dalam aplikasi). Namun, ketika ditekan, saya tidak tahu kenapa.
Saya ingin mengetahui alasan teknis untuk ini (dengan cara yang bisa saya jelaskan kepada seseorang nanti).
Adakah yang bisa membantu saya merumuskan jawaban yang bagus?
Jawaban:
Saya percaya sentimen ini benar pada satu titik, tetapi tidak dalam versi SQL Server saat ini. Seluruh masalah adalah bahwa di masa lalu pernyataan SQL ad hoc tidak dapat dioptimalkan dengan benar karena SQL Server hanya bisa mengoptimalkan / mengkompilasi pada tingkat batch. Sekarang kami memiliki optimasi tingkat pernyataan, sehingga kueri yang diparameterisasi dengan benar dari aplikasi dapat memanfaatkan rencana eksekusi yang sama dengan kueri yang tertanam dalam prosedur tersimpan.
Saya masih lebih suka prosedur tersimpan dari sisi DBA karena alasan berikut (dan beberapa dari mereka dapat memiliki dampak besar pada kinerja):
sys.sql_modules
,, untuk referensi ke objek tertentu) membuat hidup semua orang lebih mudah.SET ANSI_WARNINGS ON
, dan yang lainnya dapatSET ANSI_WARNINGS OFF
, dan mereka masing-masing akan memiliki salinan rencana mereka sendiri. Paket yang mereka peroleh tergantung pada parameter yang digunakan, statistik yang berlaku, dll. Saat pertama kali kueri dipanggil dalam setiap kasus, yang dapat mengarah ke paket yang berbeda dan karenanya kinerja yang sangat berbeda.Karena itu, pertanyaan ini kemungkinan akan membangkitkan lebih banyak argumen keagamaan daripada debat teknis. Jika kita melihat itu terjadi, kita mungkin akan mematikannya.
sumber
Sementara saya menghormati pengirim, saya dengan rendah hati tidak setuju dengan jawaban yang diberikan dan bukan karena "alasan agama". Dengan kata lain, saya percaya tidak ada fasilitas yang disediakan Microsoft yang mengurangi kebutuhan akan panduan untuk menggunakan prosedur tersimpan.
Setiap panduan yang diberikan kepada pengembang yang mendukung penggunaan kueri teks SQL mentah harus diisi dengan banyak peringatan, sehingga saya pikir saran yang paling bijaksana adalah mendorong penggunaan Prosedur yang Disimpan dan, mencegah tim pengembang Anda untuk terlibat dalam praktik. menanamkan pernyataan SQL dalam kode, atau mengirimkan permintaan SQL mentah, berbasis teks biasa, di luar SQL SPROCs (prosedur tersimpan).
Saya pikir jawaban sederhana untuk pertanyaan mengapa menggunakan SPROC adalah sebagai submitter yang diperkirakan: SPROC diuraikan, dioptimalkan, dan dikompilasi. Dengan demikian, rencana kueri / eksekusi mereka di-cache karena Anda telah menyimpan representasi statis dari sebuah query dan Anda, biasanya, akan memvariasikannya hanya dengan parameter, yang tidak benar dalam kasus pernyataan SQL yang disalin / ditempelkan yang kemungkinan berubah dari halaman-ke-halaman-dan komponen / tingkat, dan sering divariasikan sejauh tabel yang berbeda, bahkan nama database, dapat ditentukan dari panggilan ke panggilan. Mengizinkan jenis dinamis ad hoc iniPengiriman SQL, sangat mengurangi kemungkinan Mesin DB untuk menggunakan kembali rencana permintaan untuk pernyataan ad hoc Anda, menurut beberapa aturan yang sangat ketat. Di sini, saya membuat perbedaan antara permintaan ad hoc dinamis (sesuai dengan pertanyaan yang diajukan) versus penggunaan Sistem SPROC sp_executesql yang efisien.
Lebih khusus lagi, ada komponen berikut:
Ketika pernyataan SQL dikeluarkan dari halaman web, disebut "pernyataan ad hoc", mesin mencari rencana eksekusi yang ada untuk menangani permintaan tersebut. Karena ini adalah teks yang dikirimkan dari pengguna, itu akan dicerna, diuraikan, dikompilasi, dan dieksekusi, jika valid. Saat ini ia akan menerima biaya permintaan nol. Biaya permintaan digunakan ketika mesin DB menggunakan algoritme untuk menentukan rencana eksekusi mana yang akan diusir dari cache.
Kueri ad hoc menerima nilai biaya kueri asli nol, secara default. Setelah eksekusi selanjutnya dari teks kueri ad hoc yang sama persis, oleh proses pengguna lain (atau yang sama), biaya permintaan saat ini diatur ulang ke biaya kompilasi asli. Karena biaya kompilasi permintaan ad hoc kami adalah nol, ini bukan pertanda baik untuk kemungkinan penggunaan kembali. Jelas, nol adalah bilangan bulat yang paling tidak dihargai, tetapi mengapa itu harus digusur?
Ketika tekanan memori muncul, dan mereka akan melakukannya jika Anda memiliki situs yang sering digunakan, mesin DB menggunakan algoritma pembersihan untuk menentukan bagaimana ia dapat memperoleh kembali memori yang menggunakan cache Prosedur. Ia menggunakan biaya permintaan saat ini untuk memutuskan rencana mana yang akan digusur. Seperti yang Anda duga, paket dengan biaya nol adalah yang pertama diusir dari cache karena nol pada dasarnya berarti "tidak ada pengguna saat ini, atau referensi untuk, paket ini".
Oleh karena itu, sangat mungkin bahwa rencana seperti itu akan digusur terlebih dahulu ketika tekanan ingatan muncul.
Jadi, jika Anda memiliki server build-out dengan banyak memori "di luar kebutuhan Anda", Anda mungkin tidak mengalami masalah ini sesering server sibuk yang hanya memiliki "cukup" memori untuk menangani beban kerjanya. (Maaf, kapasitas dan pemanfaatan memori server agak subyektif / relatif, meskipun algoritme tidak.)
Sekarang, jika saya secara faktual salah tentang satu atau lebih poin, saya tentu terbuka untuk dikoreksi.
Terakhir, penulis menulis:
"Sekarang kami memiliki optimasi tingkat pernyataan, sehingga kueri yang diparameterisasi dengan benar dari aplikasi dapat memanfaatkan rencana eksekusi yang sama dengan kueri yang tertanam dalam prosedur tersimpan."
Saya yakin penulis mengacu pada opsi "optimalkan untuk beban kerja ad hoc".
Jika demikian, opsi ini memungkinkan untuk proses dua langkah yang menghindari segera mengirim paket permintaan penuh ke cache Prosedur. Itu hanya mengirim potongan permintaan yang lebih kecil di sana. Jika panggilan kueri yang tepat dikirim kembali ke server saat rintisan kueri masih dalam cache Prosedur, rencana eksekusi kueri lengkap disimpan ke cache Prosedur, pada saat itu. Ini menghemat memori, yang selama insiden tekanan memori, mungkin memungkinkan algoritma penggusuran untuk mengusir rintisan Anda lebih jarang daripada rencana permintaan yang lebih besar yang cache. Sekali lagi, ini tergantung pada memori dan pemanfaatan server Anda.
Namun, Anda harus mengaktifkan opsi ini, karena tidak aktif secara default.
Terakhir, saya ingin menekankan bahwa, seringkali, alasan utama pengembang menanamkan SQL di halaman, komponen, dan tempat-tempat lain, adalah karena mereka ingin menjadi fleksibel dan mengirimkan query SQL dinamis ke mesin database. Oleh karena itu, dalam Kasus Penggunaan dunia nyata, mengirimkan teks yang sama, panggilan-panggilan, tidak mungkin terjadi seperti halnya caching / efisiensi yang kami cari, ketika mengirimkan permintaan ad hoc ke SQL Server.
Untuk informasi tambahan, silakan lihat:
https://technet.microsoft.com/en-us/library/ms181055(v=sql.105).aspx
http://sqlmag.com/database-performance-tuning/don-t-fear-dynamic-sql
Terbaik,
Henry
sumber
TLDR: Tidak ada perbedaan kinerja yang cukup besar antara keduanya selama inline sql Anda parameter.
Inilah alasan mengapa saya secara bertahap menghapus prosedur tersimpan:
Kami menjalankan lingkungan aplikasi 'beta' - lingkungan yang paralel dengan produksi yang berbagi basis data produksi. Karena, kode db berada pada tingkat aplikasi dan perubahan struktur db jarang terjadi, kami dapat memungkinkan orang untuk mengkonfirmasi fungsionalitas baru di luar QA dan melakukan penyebaran di luar jendela penyebaran produksi tetapi masih menyediakan fungsionalitas produksi dan perbaikan tidak kritis. Ini tidak akan mungkin terjadi jika setengah dari kode aplikasi ada dalam DB.
Kami berlatih devops di tingkat basis data (gurita + dacpacs). Namun, sementara lapisan bisnis ke atas pada dasarnya dapat dibersihkan dan diganti dan pemulihan hanya sebaliknya, itu tidak benar untuk perubahan tambahan dan berpotensi merusak yang harus pergi ke database. Karenanya, kami memilih untuk menjaga penyebaran DB kami lebih ringan dan lebih jarang.
Untuk menghindari salinan yang persis sama dari kode yang sama untuk parameter opsional, kita sering akan menggunakan pola 'di mana @var adalah null atau @ var = table.field'. Dengan proc yang tersimpan, Anda kemungkinan akan mendapatkan rencana eksekusi yang sama, meskipun ada maksud yang agak berbeda, dan karenanya mengalami masalah kinerja atau menghilangkan rencana yang di-cache dengan petunjuk 'kompilasi ulang'. Namun, dengan sedikit kode sederhana yang menambahkan komentar "tanda tangan" di akhir sql, kita dapat memaksa rencana berbeda berdasarkan variabel mana yang nol (tidak dapat ditafsirkan sebagai rencana yang berbeda untuk semua kombinasi variabel - hanya nol vs bukan null).
Saya bisa membuat perubahan dramatis pada hasil dengan hanya perubahan kecil dengan cepat ke sql. Misalnya, saya dapat memiliki pernyataan yang ditutup dengan dua CTE, "Raw", dan "ReportReady". Tidak ada yang mengatakan kedua CTE harus digunakan. Pernyataan sql saya kemudian dapat:
...
pilih * dari {(format)} "
Ini memungkinkan saya untuk menggunakan metode logika bisnis yang sama persis untuk panggilan api yang ramping dan laporan yang perlu lebih rinci memastikan bahwa saya tidak menduplikasi logika yang rumit.
Ada alasan yang sah untuk menggunakan procs:
Keamanan - Anda punya lapisan lain di sini yang harus dilalui aplikasi. Jika akun layanan aplikasi tidak diperbolehkan menyentuh tabel, tetapi hanya memiliki izin 'jalankan' pada procs, Anda memiliki perlindungan ekstra. Ini tidak membuatnya diberikan karena memang ada biaya, tetapi itu adalah kemungkinan.
Penggunaan Kembali - Walaupun saya akan mengatakan bahwa penggunaan kembali sebagian besar harus terjadi pada lapisan bisnis untuk memastikan Anda tidak melewati aturan bisnis yang terkait dengan non-db, kami masih memiliki jenis procs dan fungsi utilitas "digunakan di mana saja" tingkat rendah yang digunakan di mana-mana ".
Ada beberapa argumen yang tidak benar-benar mendukung procs atau IMO yang mudah dimitigasi:
Penggunaan Kembali - Saya menyebutkan ini di atas sebagai "plus", tetapi juga ingin menyebutkannya di sini bahwa penggunaan kembali sebagian besar harus terjadi pada lapisan bisnis. Proc untuk menyisipkan catatan tidak boleh dianggap "dapat digunakan kembali" ketika lapisan bisnis mungkin juga memeriksa layanan non-db lainnya.
Cache plan mengasapi - satu-satunya cara ini akan menjadi masalah adalah jika Anda menggabungkan nilai daripada parameterisasi. Fakta bahwa Anda jarang mendapatkan lebih dari satu paket per proc sebenarnya sering menyakiti Anda ketika Anda memiliki 'atau' dalam permintaan
Ukuran pernyataan - kb tambahan dari pernyataan sql atas nama proc biasanya akan diabaikan relatif terhadap data yang datang kembali. Jika tidak apa-apa bagi Entitas, tidak apa-apa bagi saya.
Melihat kueri yang tepat - Membuat kueri mudah ditemukan dalam kode semudah menambahkan lokasi panggilan sebagai komentar pada kode. Membuat kode dapat disalin dari kode c # ke ssms semudah beberapa interpolasi kreatif dan penggunaan komentar:
Sql Injection - Parameterkan pertanyaan Anda. Selesai Ini sebenarnya bisa dibatalkan jika proc malah menggunakan sql dinamis.
Bypassing deployment - Kami juga mempraktikkan devops di level database, jadi ini bukan pilihan bagi kami.
"Lambat dalam aplikasi, cepat dalam SSMS" - Ini adalah masalah caching paket yang mempengaruhi kedua belah pihak. Opsi yang disetel hanya menyebabkan rencana baru dikompilasi yang tampaknya memperbaiki masalah untuk variabel THE ONE SET OFF. Ini hanya menjawab mengapa Anda melihat hasil yang berbeda - opsi yang disetel sendiri TIDAK memperbaiki masalah parameter mengendus.
Paket eksekusi sql sebaris tidak di-cache - Cukup salah. Pernyataan parameter, seperti nama proc dengan cepat hash dan kemudian rencana dicari oleh hash itu. 100% sama.
Untuk lebih jelasnya saya berbicara tentang sql inline mentah bukan kode yang dihasilkan dari ORM - kami hanya menggunakan Dapper yang merupakan ORM mikro yang terbaik.
https://weblogs.asp.net/fbouma/38178
/programming//a/15277/852208
sumber