Các kế hoạch thực thi
Nó phức tạp hơn bạn có thể mong đợi để biết từ thông tin được cung cấp trong kế hoạch thực thi nếu một câu lệnh SQL sử dụng tham số hóa đơn giản . Không có gì ngạc nhiên ngay cả những người dùng SQL Server có kinh nghiệm cao cũng có xu hướng hiểu sai điều này, do thông tin mâu thuẫn thường được cung cấp cho chúng tôi.
Hãy xem một số ví dụ sử dụng cơ sở dữ liệu Stack Overflow 2010 trên SQL Server 2019 CU 14, với khả năng tương thích cơ sở dữ liệu được đặt thành 150.
Để bắt đầu, chúng tôi sẽ cần một chỉ mục không phân nhánh mới:
CREATE INDEX [IX dbo.Users Reputation (DisplayName)] ON dbo.Users (Reputation) INCLUDE (DisplayName);
1. Đã áp dụng tham số đơn giản
Truy vấn mẫu đầu tiên này sử dụng tham số hóa đơn giản :
SELECT U.DisplayName FROM dbo.Users AS U WHERE U.Reputation = 999;
ước tính (trước khi thực hiện) kế hoạch có các yếu tố liên quan đến tham số hóa sau:
Thuộc tính tham số kế hoạch ước tính
Lưu ý @1
tham số được giới thiệu ở mọi nơi ngoại trừ văn bản truy vấn được hiển thị ở trên cùng.
thực tế (sau khi thực hiện) kế hoạch có:
Thuộc tính tham số kế hoạch thực tế
Lưu ý rằng cửa sổ thuộc tính hiện đã mất ParameterizedText
, đồng thời thu được thông tin về giá trị thời gian chạy tham số. Văn bản truy vấn được tham số hóa hiện được hiển thị trên đầu cửa sổ với ‘@1
'Thay vì' 999 '.
2. Tham số đơn giản không được áp dụng
Ví dụ thứ hai này không sử dụng tham số hóa đơn giản:
-- Projecting an extra column SELECT U.DisplayName, U.CreationDate -- NEW FROM dbo.Users AS U WHERE U.Reputation = 999;
ước tính kế hoạch cho thấy:
Kế hoạch không tham số ước tính
Lần này, tham số @1
bị thiếu trong Tìm kiếm chỉ mục chú giải công cụ, nhưng văn bản được tham số hóa và các phần tử danh sách tham số khác giống như trước.
Hãy xem xét thực tế kế hoạch thực hiện:
Phương án thực tế không tham số
Kết quả giống với tham số thực tế trước đó kế hoạch, ngoại trừ bây giờ là Tìm kiếm chỉ mục chú giải công cụ hiển thị giá trị không được tham số hóa ‘999’. Văn bản truy vấn được hiển thị trên cùng sử dụng @1
đánh dấu tham số. Cửa sổ thuộc tính cũng sử dụng @1
và hiển thị giá trị thời gian chạy của tham số.
Truy vấn không phải là một câu lệnh được tham số hóa bất chấp tất cả các bằng chứng ngược lại.
3. Tham số hóa không thành công
Ví dụ thứ ba của tôi cũng không được tham số hóa bởi máy chủ:
-- LOWER function used SELECT U.DisplayName, LOWER(U.DisplayName) FROM dbo.Users AS U WHERE U.Reputation = 999;
ước tính kế hoạch là:
Không thể tham số kế hoạch ước tính
Không có đề cập đến @1
tham số ở bất kỳ đâu bây giờ và Danh sách tham số phần của cửa sổ thuộc tính bị thiếu.
thực tế kế hoạch thực hiện giống nhau, vì vậy tôi sẽ không bận tâm đến việc hiển thị nó.
4. Kế hoạch song song song song
Tôi muốn cho bạn thấy thêm một ví dụ sử dụng song song trong kế hoạch thực thi. Chi phí ước tính thấp cho các truy vấn thử nghiệm của tôi có nghĩa là chúng tôi cần giảm ngưỡng chi phí cho tính song song xuống 1:
EXECUTE sys.sp_configure @configname = 'cost threshold for parallelism', @configvalue = 1; RECONFIGURE;
Ví dụ lần này phức tạp hơn một chút:
SELECT U.DisplayName FROM dbo.Users AS U WHERE U.Reputation >= 5 AND U.DisplayName > N'ZZZ' ORDER BY U.Reputation DESC;
ước tính kế hoạch thực hiện là:
Phương án tham số song song ước tính
Văn bản truy vấn trên cùng vẫn chưa được phân loại trong khi mọi thứ khác đều như vậy. Hiện có hai điểm đánh dấu tham số, @1
và @2
, bởi vì tham số hóa đơn giản đã tìm thấy hai giá trị chữ phù hợp.
thực tế kế hoạch thực hiện theo mẫu của ví dụ 1:
Phương án tham số song song thực tế
Văn bản truy vấn trên cùng hiện đã được tham số hóa và cửa sổ thuộc tính chứa các giá trị tham số thời gian chạy. Kế hoạch song song này ( với a Sắp xếp toán tử) chắc chắn được máy chủ tham số hóa bằng cách sử dụng tham số hóa đơn giản .
Phương pháp đáng tin cậy
Có những lý do cho tất cả các hành vi được hiển thị cho đến nay, và một số lý do khác bên cạnh đó. Tôi sẽ cố gắng giải thích nhiều điều này trong phần tiếp theo của loạt bài này khi tôi trình bày về việc biên soạn kế hoạch.
Trong khi đó, tình hình với showplan nói chung, và SSMS nói riêng, ít lý tưởng hơn. Điều này thật khó hiểu đối với những người đã làm việc với SQL Server trong toàn bộ sự nghiệp của họ. Bạn tin tưởng vào các điểm đánh dấu thông số nào và bạn bỏ qua những điểm đánh dấu thông số nào?
Có một số phương pháp đáng tin cậy để xác định xem một câu lệnh cụ thể có áp dụng thành công tham số hóa đơn giản cho nó hay không.
Cửa hàng Truy vấn
Tôi sẽ bắt đầu với một trong những tiện ích nhất, cửa hàng truy vấn. Thật không may, nó không phải lúc nào cũng đơn giản như bạn tưởng tượng.
Bạn phải bật tính năng lưu trữ truy vấn cho ngữ cảnh cơ sở dữ liệu nơi câu lệnh được thực thi và OPERATION_MODE
phải được đặt thành READ_WRITE
, cho phép cửa hàng truy vấn chủ động thu thập dữ liệu.
Sau khi đáp ứng các điều kiện này, đầu ra chương trình sau khi thực thi chứa các thuộc tính bổ sung, bao gồm cả StatementParameterizationType . Như tên cho thấy, điều này chứa mã mô tả kiểu tham số hóa được sử dụng cho câu lệnh.
Nó hiển thị trong cửa sổ thuộc tính SSMS khi nút gốc của một kế hoạch được chọn:
StatementParameterizationType
Các giá trị được ghi lại trong sys.query_store_query
:
- 0 - Không có
- 1 - Người dùng (tham số hóa rõ ràng)
- 2 - Tham số hóa đơn giản
- 3 - Tham số bắt buộc
Thuộc tính có lợi này chỉ xuất hiện trong SSMS khi một thực tế kế hoạch được yêu cầu và bị thiếu khi một ước tính kế hoạch được chọn. Điều quan trọng cần nhớ là kế hoạch phải được lưu vào bộ nhớ đệm . Yêu cầu một ước tính kế hoạch từ SSMS không lưu vào bộ nhớ cache kế hoạch đã tạo (kể từ SQL Server 2012).
Sau khi kế hoạch được lưu vào bộ nhớ đệm, StatementParameterizationType xuất hiện ở những nơi thông thường, bao gồm qua sys.dm_exec_query_plan
.
Bạn cũng có thể tin tưởng loại tham số địa điểm khác được ghi lại trong cửa hàng truy vấn, chẳng hạn như query_parameterization_type_desc
trong sys.query_store_query
.
Một lưu ý quan trọng. Khi truy vấn lưu trữ OPERATION_MODE
được đặt thành READ_ONLY
, StatementParameterizationType thuộc tính vẫn được điền trong SSMS thực tế kế hoạch — nhưng nó luôn luôn là 0 —Có ấn tượng sai, câu lệnh không được tham số hóa khi nó có thể là như vậy.
Nếu bạn hài lòng khi bật cửa hàng truy vấn, hãy chắc chắn rằng nó đọc-ghi và chỉ xem xét các kế hoạch sau khi thực thi trong SSMS, điều này sẽ hiệu quả với bạn.
Dự đoán kế hoạch chuẩn
Văn bản truy vấn được hiển thị trên đầu cửa sổ kế hoạch đồ họa trong SSMS không đáng tin cậy, như các ví dụ đã hiển thị. Bạn cũng không thể dựa vào Danh sách tham số được hiển thị trong Thuộc tính cửa sổ khi nút gốc của kế hoạch được chọn. ParameterizedText thuộc tính được hiển thị cho ước tính chỉ kế hoạch cũng không phải là kết luận.
Tuy nhiên, bạn có thể dựa vào các thuộc tính được liên kết với các nhà khai thác gói riêng lẻ. Các ví dụ đã cho cho thấy chúng có trong chú giải công cụ khi di chuột qua một toán tử.
Vị từ có chứa điểm đánh dấu tham số như @1
hoặc @2
chỉ ra một kế hoạch được tham số hóa. Các toán tử có nhiều khả năng chứa tham số nhất là Quét chỉ mục , Tìm kiếm chỉ mục và Bộ lọc .
Dự đoán bằng các dấu tham số
Nếu việc đánh số bắt đầu bằng @1
, nó sử dụng tham số hóa đơn giản . Tham số bắt buộc bắt đầu bằng @0
. Tôi nên đề cập đến sơ đồ đánh số được ghi lại ở đây có thể thay đổi bất cứ lúc nào:
Cảnh báo thay đổi
Tuy nhiên, đây là phương pháp tôi sử dụng thường xuyên nhất để xác định xem một kế hoạch có phải tuân theo tham số hóa phía máy chủ hay không. Nhìn chung, việc kiểm tra kế hoạch một cách trực quan cho các vị từ chứa các dấu tham số thường nhanh chóng và dễ dàng. Phương pháp này cũng hoạt động cho cả hai loại kế hoạch, ước tính và thực tế .
Đối tượng quản lý động
Có một số cách để truy vấn bộ đệm kế hoạch và các DMO có liên quan để xác định xem một câu lệnh có được tham số hóa hay không. Đương nhiên, các truy vấn này chỉ hoạt động trên các kế hoạch trong bộ nhớ cache, vì vậy câu lệnh phải được thực thi để hoàn thành, được lưu vào bộ nhớ cache và sau đó không bị loại bỏ vì bất kỳ lý do gì.
Cách tiếp cận trực tiếp nhất là tìm kiếm một Adhoc lập kế hoạch sử dụng kết hợp văn bản SQL chính xác với tuyên bố quan tâm. Adhoc kế hoạch sẽ là một vỏ có chứa ParameterizedPlanHandle nếu câu lệnh được tham số hóa bởi máy chủ. Sau đó, xử lý kế hoạch được sử dụng để xác định vị trí Đã chuẩn bị kế hoạch. An Adhoc kế hoạch sẽ không tồn tại nếu tính năng tối ưu hóa cho khối lượng công việc đột xuất được bật và câu lệnh được đề cập chỉ được thực thi một lần.
Loại truy vấn này thường kết thúc việc băm nhỏ một lượng đáng kể XML và quét toàn bộ bộ nhớ cache của kế hoạch ít nhất một lần. Cũng dễ dàng nhận được sai mã, đặc biệt là vì các kế hoạch trong bộ nhớ cache bao gồm toàn bộ lô. Một lô có thể chứa nhiều câu lệnh, mỗi câu lệnh có thể được tham số hóa hoặc không. Không phải tất cả các DMO đều hoạt động ở cùng một mức độ chi tiết (lô hoặc câu lệnh), khiến nó khá dễ bị gỡ bỏ.
Dưới đây là một cách hiệu quả để liệt kê các tuyên bố quan tâm, cùng với các phân đoạn kế hoạch cho những tuyên bố riêng lẻ đó:
SELECT StatementText = SUBSTRING(T.[text], 1 + (QS.statement_start_offset / 2), 1 + ((QS.statement_end_offset - QS.statement_start_offset) / 2)), IsParameterized = IIF(T.[text] LIKE N'(%', 'Yes', 'No'), query_plan = TRY_CONVERT(xml, P.query_plan) FROM sys.dm_exec_query_stats AS QS CROSS APPLY sys.dm_exec_sql_text (QS.[sql_handle]) AS T CROSS APPLY sys.dm_exec_text_query_plan ( QS.plan_handle, QS.statement_start_offset, QS.statement_end_offset) AS P WHERE -- Statements of interest T.[text] LIKE N'%DisplayName%Users%' -- Exclude queries like this one AND T.[text] NOT LIKE N'%sys.dm%' ORDER BY QS.last_execution_time ASC, QS.statement_start_offset ASC;
Để minh họa, hãy chạy một lô duy nhất chứa bốn ví dụ trước đó:
ALTER DATABASE SCOPED CONFIGURATION CLEAR PROCEDURE_CACHE; GO -- Example 1 SELECT U.DisplayName FROM dbo.Users AS U WHERE U.Reputation = 999; -- Example 2 SELECT U.DisplayName, U.CreationDate FROM dbo.Users AS U WHERE U.Reputation = 999; -- Example 3 SELECT U.DisplayName, LOWER(U.DisplayName) FROM dbo.Users AS U WHERE U.Reputation = 999; -- Example 4 SELECT U.DisplayName FROM dbo.Users AS U WHERE U.Reputation >= 5 AND U.DisplayName > N'ZZZ' ORDER BY U.Reputation DESC; GO
Đầu ra của truy vấn DMO là:
Kết quả truy vấn DMO
Điều này xác nhận chỉ ví dụ 1 và 4 đã được tham số hóa thành công.
Bộ đếm Hiệu suất
Có thể sử dụng bộ đếm hiệu suất Thống kê SQL để có được thông tin chi tiết về hoạt động tham số hóa cho cả ước tính và thực tế các kế hoạch. Các bộ đếm được sử dụng không tính theo phạm vi mỗi phiên, vì vậy bạn sẽ cần sử dụng phiên bản thử nghiệm không có hoạt động đồng thời nào khác để có được kết quả chính xác.
Tôi sẽ bổ sung thông tin bộ đếm tham số hóa với dữ liệu từ sys.dm_exec_query_optimizer_info
DMO để cung cấp số liệu thống kê về các kế hoạch tầm thường.
Cần phải cẩn thận để ngăn các câu lệnh đọc thông tin bộ đếm tự sửa đổi các bộ đếm đó. Tôi sẽ giải quyết vấn đề này bằng cách tạo một số thủ tục được lưu trữ tạm thời:
CREATE PROCEDURE #TrivialPlans AS SET NOCOUNT ON; SELECT OI.[counter], OI.occurrence FROM sys.dm_exec_query_optimizer_info AS OI WHERE OI.[counter] = N'trivial plan'; GO CREATE PROCEDURE #PerfCounters AS SET NOCOUNT ON; SELECT PC.[object_name], PC.counter_name, PC.cntr_value FROM sys.dm_os_performance_counters AS PC WHERE PC.counter_name LIKE N'%Param%';
Sau đó, tập lệnh để kiểm tra một câu lệnh cụ thể sẽ trông giống như sau:
ALTER DATABASE SCOPED CONFIGURATION CLEAR PROCEDURE_CACHE; GO EXECUTE #PerfCounters; EXECUTE #TrivialPlans; GO SET SHOWPLAN_XML ON; GO -- The statement(s) under test: -- Example 3 SELECT U.DisplayName, LOWER(U.DisplayName) FROM dbo.Users AS U WHERE U.Reputation = 999; GO SET SHOWPLAN_XML OFF; GO EXECUTE #TrivialPlans; EXECUTE #PerfCounters;
Nhận xét SHOWPLAN_XML
hàng loạt để chạy (các) câu lệnh đích và nhận được thực tế các kế hoạch. Để chúng đúng vị trí cho ước tính kế hoạch thực hiện.
Chạy toàn bộ nội dung như đã viết sẽ cho kết quả sau:
Kết quả kiểm tra bộ đếm hiệu suất
Tôi đã đánh dấu ở trên nơi các giá trị đã thay đổi khi thử nghiệm ví dụ 3.
Sự gia tăng trong bộ đếm "kế hoạch tầm thường" từ 1050 lên 1051 cho thấy một kế hoạch nhỏ đã được tìm thấy cho tuyên bố thử nghiệm.
Bộ đếm tham số hóa đơn giản đã tăng 1 cho cả lần thử và lần thất bại, cho thấy Máy chủ SQL đã cố gắng tham số hóa câu lệnh, nhưng không thành công.
Kết thúc Phần 3
Trong phần tiếp theo của loạt bài này, tôi sẽ giải thích những điều tò mò mà chúng tôi đã thấy bằng cách mô tả cách tham số hóa đơn giản và kế hoạch tầm thường tương tác với quá trình biên dịch.
Nếu bạn đã thay đổi ngưỡng chi phí cho tính năng song song để chạy các ví dụ, hãy nhớ đặt lại nó (của tôi được đặt thành 50):
EXECUTE sys.sp_configure @configname = 'cost threshold for parallelism', @configvalue = 50; RECONFIGURE;