Sqlserver
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Sqlserver

Khi nào thì tốt hơn nên viết sql ad hoc so với các thủ tục được lưu trữ

SQL Server lưu trữ các kế hoạch thực thi cho các truy vấn đặc biệt, do đó (giảm thời gian thực hiện của cuộc gọi đầu tiên) hai cách tiếp cận sẽ giống nhau về tốc độ.

Nói chung, việc sử dụng các thủ tục được lưu trữ có nghĩa là lấy một phần mã mà ứng dụng của bạn cần (các truy vấn T-SQL) và đặt nó vào một nơi không được kiểm soát nguồn (nó có thể được, nhưng thường thì không phải ) và nơi người khác có thể thay đổi nó mà bạn không biết.

Đặt các truy vấn ở vị trí trung tâm như thế này có thể là một điều tốt, tùy thuộc vào số lượng ứng dụng khác nhau cần quyền truy cập vào dữ liệu mà chúng đại diện. Nhìn chung, tôi thấy việc giữ các truy vấn được ứng dụng cư trú trong mã ứng dụng sử dụng dễ dàng hơn nhiều.

Vào giữa những năm 1990, sự khôn ngoan thông thường cho rằng các thủ tục được lưu trữ trong SQL Server là cách để áp dụng trong các tình huống quan trọng về hiệu suất và tại thời điểm đó chắc chắn là như vậy. Tuy nhiên, những lý do đằng sau CW này đã không còn giá trị trong một thời gian dài.

Cập nhật: Ngoài ra, thường xuyên trong các cuộc tranh luận về khả năng tồn tại của các thủ tục được lưu trữ, nhu cầu ngăn chặn việc tiêm SQL được đưa ra để bảo vệ các procs. Chắc chắn, không ai có suy nghĩ đúng đắn của họ nghĩ rằng việc tập hợp các truy vấn đặc biệt thông qua nối chuỗi là điều chính xác phải làm (mặc dù điều này sẽ chỉ khiến bạn bị tấn công SQL injection nếu bạn đang nối đầu vào của người dùng ). Rõ ràng là các truy vấn đặc biệt nên được tham số hóa, không chỉ để ngăn chặn con quái vật dưới gầm giường của một cuộc tấn công tiêm sql, mà còn để làm cho cuộc sống của bạn với tư cách là một lập trình viên nói chung dễ dàng hơn (trừ khi bạn thích phải tìm ra khi nào sử dụng đơn trích dẫn xung quanh các giá trị của bạn).

Cập nhật 2: Tôi đã thực hiện nhiều nghiên cứu hơn. Dựa trên Sách trắng MSDN này , có vẻ như câu trả lời phụ thuộc vào ý bạn muốn nói "đặc biệt" với các truy vấn của mình. Ví dụ:một truy vấn đơn giản như sau:

SELECT ID, DESC FROM tblSTUFF WHERE ITEM_COUNT > 5

... sẽ có kế hoạch thực thi của nó được lưu vào bộ nhớ đệm. Hơn nữa, vì truy vấn không chứa các phần tử loại bỏ nhất định (giống như gần như bất kỳ thứ gì khác ngoài một SELECT đơn giản từ một bảng), SQL Server sẽ thực sự "tự động tham số hóa" truy vấn và thay thế hằng số "5" bằng một tham số và bộ nhớ cache kế hoạch thực thi cho phiên bản được tham số hóa. Điều này có nghĩa là nếu sau đó bạn thực thi this truy vấn đặc biệt:

SELECT ID, DESC FROM tblSTUFF WHERE ITEM_COUNT > 23

... nó sẽ có thể sử dụng kế hoạch thực thi được lưu trong bộ nhớ cache.

Rất tiếc, danh sách các phần tử truy vấn không đủ điều kiện cho tham số hóa tự động rất dài (ví dụ:quên sử dụng DISTINCT , TOP , UNION , GROUP BY , OR v.v.), vì vậy bạn thực sự không thể tin tưởng vào điều này cho hiệu suất.

Nếu bạn có một truy vấn "siêu phức tạp" sẽ không được tham số hóa tự động, như:

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

... nó vẫn sẽ được lưu vào bộ nhớ đệm theo văn bản chính xác của truy vấn, vì vậy nếu ứng dụng của bạn gọi truy vấn này với cùng các giá trị "mã hóa cứng" theo nghĩa đen lặp đi lặp lại, mỗi truy vấn sau truy vấn đầu tiên sẽ sử dụng lại kế hoạch thực thi đã lưu trong bộ nhớ cache (và do đó nhanh như một proc được lưu trữ).

Nếu các giá trị theo nghĩa đen thay đổi (dựa trên hành động của người dùng, chẳng hạn như lọc hoặc sắp xếp dữ liệu đã xem), thì các truy vấn sẽ không được hưởng lợi từ bộ nhớ đệm (trừ khi chúng vô tình khớp chính xác với một truy vấn gần đây).

Cách để hưởng lợi từ bộ nhớ đệm với các truy vấn "đặc biệt" là tham số hóa chúng. Tạo truy vấn nhanh trong C # như thế này:

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

là không chính xác. Cách chính xác (sử dụng ADO.Net) sẽ như thế này:

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();
}

Truy vấn không chứa các ký tự và đã được tham số hóa đầy đủ, vì vậy các truy vấn tiếp theo sử dụng câu lệnh được tham số hóa giống hệt nhau sẽ sử dụng kế hoạch được lưu trong bộ nhớ cache (ngay cả khi được gọi với các giá trị tham số khác nhau). Lưu ý rằng mã ở đây hầu như giống với mã mà bạn sẽ sử dụng để gọi một thủ tục được lưu trữ (sự khác biệt duy nhất là CommandType và CommandText), vì vậy nó phần nào đi xuống nơi bạn muốn văn bản của truy vấn đó "tồn tại. "(trong mã ứng dụng của bạn hoặc trong một quy trình được lưu trữ).

Cuối cùng, nếu theo truy vấn "đặc biệt", bạn có nghĩa là bạn đang xây dựng động các truy vấn với các cột, bảng, thông số lọc khác nhau và những thứ khác, có thể như sau:

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

... thì bạn khá không thể thực hiện việc này với các thủ tục được lưu trữ (không có EXEC hack vốn không được nói đến trong xã hội lịch sự), vì vậy vấn đề là tranh luận.

Cập nhật 3: Đây là điều duy nhất thực sự tốt liên quan đến hiệu suất lý do (mà tôi có thể nghĩ ra, dù sao) để sử dụng một thủ tục được lưu trữ. Nếu truy vấn của bạn là một truy vấn chạy dài trong đó quá trình biên dịch kế hoạch thực thi mất nhiều thời gian hơn so với thực thi thực tế và truy vấn chỉ được gọi không thường xuyên (như báo cáo hàng tháng chẳng hạn), thì việc đặt nó vào một thủ tục được lưu trữ có thể làm cho SQL Server giữ kế hoạch đã biên dịch trong bộ nhớ cache đủ lâu để nó vẫn còn tồn tại trong tháng tới. Mặc dù vậy, hãy đánh bại tôi nếu điều đó đúng hay không.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Sự khác biệt về hiệu suất chính giữa kiểu dữ liệu SQL Server varchar và nvarchar là gì?

  2. Lược đồ trong SQL Server là gì và cách tạo / thả lược đồ trong cơ sở dữ liệu SQL Server - Hướng dẫn sử dụng SQL Server / TSQL Phần 27

  3. Tổng quan về câu lệnh PRINT trong SQL Server

  4. chuyển đổi hàm ms-access last () sang sql server 2008

  5. Khắc phục Msg 241 “Chuyển đổi không thành công khi chuyển đổi ngày và / hoặc thời gian từ chuỗi ký tự” trong SQL Server