Sqlserver
 sql >> Teknologi Basis Data >  >> RDS >> Sqlserver

Kapan lebih baik menulis ad hoc sql vs prosedur tersimpan?

SQL Server menyimpan rencana eksekusi untuk kueri ad-hoc, jadi (dengan mengurangi waktu yang dibutuhkan oleh panggilan pertama) kedua pendekatan akan identik dalam hal kecepatan.

Secara umum, penggunaan prosedur tersimpan berarti mengambil sebagian dari kode yang dibutuhkan oleh aplikasi Anda (kueri T-SQL) dan meletakkannya di tempat yang tidak berada di bawah kendali sumber (itu dapat menjadi, tapi biasanya tidak ) dan di mana itu dapat diubah oleh orang lain tanpa sepengetahuan Anda.

Memiliki pertanyaan di tempat sentral seperti ini mungkin menjadi hal yang baik, tergantung pada berapa banyak aplikasi yang berbeda membutuhkan akses ke data yang mereka wakili. Saya biasanya merasa jauh lebih mudah untuk menyimpan kueri yang digunakan oleh penduduk aplikasi dalam kode aplikasi itu sendiri.

Pada pertengahan 1990-an, kebijaksanaan konvensional mengatakan bahwa prosedur tersimpan di SQL Server adalah cara yang harus dilakukan dalam situasi kritis kinerja, dan pada saat itu memang demikian. Namun, alasan di balik CW ini tidak valid untuk waktu yang lama.

Pembaruan: Juga, sering dalam perdebatan tentang kelangsungan prosedur tersimpan, kebutuhan untuk mencegah injeksi SQL dipanggil untuk membela procs. Tentunya, tidak ada orang waras yang berpikir bahwa merakit kueri ad hoc melalui penggabungan string adalah hal yang benar untuk dilakukan (walaupun ini hanya akan membuat Anda terkena serangan injeksi SQL jika Anda menggabungkan input pengguna ). Jelas kueri ad hoc harus diparameterisasi, tidak hanya untuk mencegah monster-under-the-bed dari serangan injeksi sql, tetapi juga hanya untuk membuat hidup Anda sebagai programmer umumnya lebih mudah (kecuali jika Anda senang harus mencari tahu kapan harus menggunakan single mengutip nilai-nilai Anda).

Pembaruan 2: Saya telah melakukan lebih banyak penelitian. Berdasarkan buku putih MSDN ini , tampaknya jawabannya tergantung pada apa yang Anda maksud dengan "ad-hoc" dengan pertanyaan Anda, tepatnya. Misalnya, kueri sederhana seperti ini:

SELECT ID, DESC FROM tblSTUFF WHERE ITEM_COUNT > 5

... akan memiliki rencana eksekusi di-cache. Selain itu, karena kueri tidak mengandung elemen pendiskualifikasi tertentu (seperti hampir semua hal selain SELECT sederhana dari satu tabel), SQL Server akan benar-benar "memparameterisasi otomatis" kueri dan mengganti konstanta literal "5" dengan parameter, dan cache rencana eksekusi untuk versi parameter. Ini berarti bahwa jika Anda kemudian menjalankan ini kueri ad-hoc:

SELECT ID, DESC FROM tblSTUFF WHERE ITEM_COUNT > 23

... itu akan dapat menggunakan rencana eksekusi yang di-cache.

Sayangnya, daftar elemen kueri yang mendiskualifikasi untuk parameterisasi otomatis panjang (misalnya, lupakan penggunaan DISTINCT , TOP , UNION , GROUP BY , OR dll.), jadi Anda benar-benar tidak dapat mengandalkan ini untuk kinerja.

Jika Anda memiliki kueri "super kompleks" yang tidak akan diparameterisasi secara otomatis, seperti:

SELECT ID, DESC FROM tblSTUFF WHERE ITEM_COUNT > 5 OR ITEM_COUNT < 23

... itu masih akan di-cache oleh teks kueri yang tepat, jadi jika aplikasi Anda memanggil kueri ini dengan nilai "hard-coded" literal yang sama berulang kali, setiap kueri setelah yang pertama akan menggunakan kembali rencana eksekusi yang di-cache (dan jadi secepat proc yang tersimpan).

Jika nilai literal berubah (berdasarkan tindakan pengguna, misalnya, seperti memfilter atau mengurutkan data yang dilihat), maka kueri tidak akan mendapat manfaat dari cache (kecuali kadang-kadang ketika kueri secara tidak sengaja sama persis dengan kueri terbaru).

Cara memanfaatkan caching dengan kueri "ad-hoc" adalah dengan membuat parameternya. Membuat kueri dengan cepat di C# seperti ini:

int itemCount = 5;
string query = "DELETE FROM tblSTUFF WHERE ITEM_COUNT > " + 
        itemCount.ToString();

tidak benar. Cara yang benar (menggunakan ADO.Net) adalah seperti ini:

using (SqlConnection conn = new SqlConnection(connStr))
{
    SqlCommand com = new SqlCommand(conn);
    com.CommandType = CommandType.Text;
    com.CommandText = 
        "DELETE FROM tblSTUFF WHERE ITEM_COUNT > @ITEM_COUNT";
    int itemCount = 5;
    com.Parameters.AddWithValue("@ITEM_COUNT", itemCount);
    com.Prepare();
    com.ExecuteNonQuery();
}

Kueri tidak berisi literal dan sudah sepenuhnya diparameterisasi, jadi kueri berikutnya yang menggunakan pernyataan berparameter identik akan menggunakan paket yang di-cache (bahkan jika dipanggil dengan nilai parameter yang berbeda). Perhatikan bahwa kode di sini hampir sama dengan kode yang akan Anda gunakan untuk memanggil prosedur tersimpan (satu-satunya perbedaan adalah CommandType dan CommandText), jadi agak turun ke tempat Anda ingin teks kueri itu "langsung " (dalam kode aplikasi Anda atau dalam prosedur tersimpan).

Terakhir, jika dengan kueri "ad-hoc" yang Anda maksud adalah membuat kueri secara dinamis dengan berbagai kolom, tabel, parameter pemfilteran, dan yang lainnya, mungkin seperti ini:

SELECT ID, DESC FROM tblSTUFF WHERE ITEM_COUNT > 5

SELECT ID, FIRSTNAME, LASTNAME FROM tblPEEPS 
    WHERE AGE >= 18 AND LASTNAME LIKE '%What the`

SELECT ID, FIRSTNAME, LASTNAME FROM tblPEEPS 
    WHERE AGE >= 18 AND LASTNAME LIKE '%What the`
    ORDER BY LASTNAME DESC

... maka Anda cukup banyak tidak bisa lakukan ini dengan prosedur tersimpan (tanpa EXEC hack yang tidak dibicarakan dalam masyarakat sopan), jadi intinya bisa diperdebatkan.

Pembaruan 3 Inilah satu-satunya terkait kinerja yang benar-benar bagus alasan (yang bisa saya pikirkan) untuk menggunakan prosedur tersimpan. Jika kueri Anda berjalan lama di mana proses kompilasi rencana eksekusi memakan waktu jauh lebih lama daripada eksekusi sebenarnya, dan kueri hanya jarang dipanggil (seperti laporan bulanan, misalnya), maka memasukkannya ke dalam prosedur tersimpan mungkin buat SQL Server menyimpan rencana yang dikompilasi dalam cache cukup lama agar masih ada bulan depan. Mengalahkan saya jika itu benar atau tidak.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Bagaimana Menemukan Baris yang Duplikat dengan Kunci tetapi Bukan Duplikat di Semua Kolom?

  2. Bagaimana Saya Menyalin Kumpulan Data, dan Mengubah Referensi FK untuk Menunjuk ke Semua Salinan?

  3. SQL RANK() versus ROW_NUMBER()

  4. SQL - Permintaan untuk mendapatkan alamat IP server

  5. Saran kinerja SQL Server dari Brent Ozar dan Pinal Dave