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

Tham số hóa đơn giản và các kế hoạch tầm thường - Phần 3

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@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 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 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 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 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;

  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Tham dự Hội nghị thượng đỉnh PASS ở Charlotte?

  2. ScaleGrid được xếp hạng trong số 100 nhà cung cấp dịch vụ đám mây hàng đầu

  3. Python, Ruby và Golang:So sánh ứng dụng dịch vụ web

  4. Giới thiệu về Khai thác dữ liệu

  5. Easysoft phát hành Cầu ODBC-ODBC cho Windows 10