Chuẩn bị một lô SQL riêng biệt với việc thực hiện lô SQL đã chuẩn bị là một cấu trúc có hiệu quả **vô dụng đối với SQL Server được đưa ra cách các kế hoạch thực hiện được lưu trữ. Tách các bước chuẩn bị (phân tích cú pháp, ràng buộc bất kỳ tham số nào và biên dịch) và thực thi chỉ có ý nghĩa khi không có bộ đệm. Mục đích là để tiết kiệm thời gian dành cho việc phân tích cú pháp và biên dịch bằng cách sử dụng lại một gói hiện có và đây là những gì bộ đệm của kế hoạch nội bộ thực hiện. Nhưng không phải tất cả các RDBMS đều thực hiện mức bộ nhớ đệm này (rõ ràng từ sự tồn tại của các chức năng này) và do đó, nó tùy thuộc vào mã máy khách để yêu cầu một gói được "lưu vào bộ nhớ cache" và do đó lưu ID bộ đệm đó và sau đó sử dụng lại nó Đây là gánh nặng bổ sung cho mã máy khách (và lập trình viên phải nhớ thực hiện và làm cho đúng) không cần thiết. Trong thực tế, trang MSDN cho phương thức IDbCommand.Prepare () nêu:
Máy chủ tự động lưu trữ các kế hoạch để sử dụng lại khi cần thiết; do đó, không cần phải gọi phương thức này trực tiếp trong ứng dụng khách của bạn.
Cần lưu ý rằng, theo như thử nghiệm của tôi cho thấy (phù hợp với những gì bạn hiển thị trong Câu hỏi), gọi SqlCommand.Prepare () , không thực hiện thao tác "chuẩn bị": nó gọi sp_prepexec để chuẩn bị và thực thi SQL ; nó không gọi sp_prepare là phân tích cú pháp và chỉ biên dịch (và không nhận bất kỳ giá trị tham số nào, chỉ có tên và kiểu dữ liệu của chúng). Do đó, không thể có bất kỳ lợi ích "biên dịch trước" nào khi gọi SqlCommand.Prepare
vì nó thực hiện ngay lập tức (giả sử mục tiêu là trì hoãn thực thi). TUY NHIÊN , có một lợi ích nhỏ tiềm năng thú vị của việc gọi điện SqlCommand.Prepare()
, ngay cả khi nó gọi sp_prepexec
thay vì sp_prepare
. Xin vui lòng xem ghi chú ( ** ) ở phía dưới để biết chi tiết.
Thử nghiệm của tôi cho thấy ngay cả khi SqlCommand.Prepare()
được gọi (và xin lưu ý rằng cuộc gọi này không đưa ra bất kỳ lệnh nào trên SQL Server), ExecuteNonQuery
hoặc lệnh ExecuteReader
tiếp theo được thực thi đầy đủ và nếu là ExecuteReader, nó sẽ trả về các hàng. Tuy nhiên, SQL Server Profiler cho thấy SqlCommand.Execute______()
cuộc gọi đầu tiên sau khi SqlCommand.Prepare()
đăng ký cuộc gọi là sự kiện "Chuẩn bị SQL" và các .Execute___()
cuộc gọi tiếp theo đăng ký dưới dạng sự kiện "Exec Prepared SQL".
Mã kiểm tra
Nó đã được tải lên PasteBin tại: http://pastebin.com/Yc2Tfvup . Mã này tạo ra Ứng dụng Bảng điều khiển .NET / C # dự định chạy trong khi theo dõi SQL Server Profiler đang chạy (hoặc phiên Sự kiện mở rộng). Nó tạm dừng sau mỗi bước để rõ ràng câu lệnh nào có ảnh hưởng cụ thể.
CẬP NHẬT
Tìm thấy thêm thông tin, và một lý do tiềm năng nhỏ để tránh gọi SqlCommand.Prepare()
. Một điều tôi nhận thấy trong thử nghiệm của mình và điều cần lưu ý đối với bất kỳ ai đang chạy thử nghiệm Ứng dụng Console đó: không bao giờ có một cuộc gọi rõ ràng được thực hiện sp_unprepare
. Tôi đã thực hiện một số hoạt động đào và tìm thấy bài đăng sau đây trong các diễn đàn MSDN:
SqlCommand - Chuẩn bị hay không chuẩn bị?
Câu trả lời được chấp nhận chứa một loạt thông tin, nhưng các điểm nổi bật là:
- ** Những gì chuẩn bị thực sự giúp bạn tiết kiệm chủ yếu là thời gian cần thiết để truyền chuỗi truy vấn qua dây.
- Một truy vấn đã chuẩn bị không đảm bảo kế hoạch được lưu trong bộ nhớ cache và không nhanh hơn truy vấn đặc biệt khi nó đến máy chủ.
- RPC (CommandType.StoredProcedure) không thu được gì từ việc chuẩn bị.
- Trên máy chủ, một tay cầm được chuẩn bị về cơ bản là một chỉ mục vào bản đồ trong bộ nhớ có chứa TSQL để thực thi.
- Bản đồ được lưu trữ trên cơ sở mỗi kết nối, không thể sử dụng kết nối chéo.
- Thiết lập lại được gửi khi khách hàng sử dụng lại kết nối từ nhóm xóa bản đồ.
Tôi cũng tìm thấy bài đăng sau đây từ nhóm SQLCAT, có vẻ như có liên quan, nhưng đơn giản có thể là một vấn đề cụ thể đối với ODBC trong khi SqlClient không dọn dẹp chính xác khi xử lý SqlConnection. Thật khó để nói vì bài viết SQLCAT không đề cập đến bất kỳ thử nghiệm bổ sung nào có thể giúp chứng minh điều này là nguyên nhân, chẳng hạn như xóa nhóm kết nối, v.v.
Xem ra các câu lệnh SQL đã chuẩn bị
PHẦN KẾT LUẬN
Cho rằng:
- lợi ích thực sự duy nhất của việc gọi điện
SqlCommand.Prepare()
dường như là bạn không cần gửi lại văn bản truy vấn qua mạng,
- gọi
sp_prepare
và sp_prepexec
lưu trữ văn bản truy vấn như một phần của bộ nhớ của kết nối (tức là bộ nhớ Máy chủ SQL)
Tôi muốn giới thiệu với gọi SqlCommand.Prepare()
vì lợi ích duy nhất tiềm năng tiết kiệm gói mạng trong khi nhược điểm là chiếm bộ nhớ máy chủ hơn. Mặc dù phần lớn dung lượng bộ nhớ tiêu thụ có thể rất nhỏ trong phần lớn các trường hợp, băng thông mạng hiếm khi là vấn đề vì hầu hết các máy chủ DB được kết nối trực tiếp với các máy chủ ứng dụng trên 10 Megabit tối thiểu (nhiều khả năng là 100 Megabit hoặc Gigabit trong những ngày này) ( và một số thậm chí trên cùng một hộp ;-). Điều đó và bộ nhớ gần như luôn là một nguồn tài nguyên khan hiếm hơn băng thông mạng.
Tôi cho rằng, đối với bất kỳ ai viết phần mềm có thể kết nối với nhiều cơ sở dữ liệu, thì sự tiện lợi của giao diện chuẩn có thể thay đổi phân tích chi phí / lợi ích này. Nhưng ngay cả trong trường hợp đó, tôi phải tin rằng vẫn đủ dễ dàng để trừu tượng một giao diện DB "tiêu chuẩn" cho phép các nhà cung cấp khác nhau (và do đó có sự khác biệt giữa họ, như không cần gọi Prepare()
) vì cho rằng làm như vậy là Đối tượng cơ bản Lập trình định hướng mà bạn có khả năng đã thực hiện trong mã ứng dụng của mình ;-).