Đây là phần đầu tiên của loạt bài về tham số hóa đơn giản và kế hoạch tầm thường . Hai tính năng biên dịch này được kết nối chặt chẽ với nhau và có những mục tiêu tương tự. Cả hiệu suất mục tiêu và hiệu quả đối với khối lượng công việc thường xuyên gửi các báo cáo đơn giản.
Mặc dù có những cái tên “đơn giản” và “tầm thường”, cả hai đều có những hành vi tinh vi và chi tiết triển khai có thể khiến cách chúng hoạt động khó hiểu. Loạt bài này không trình bày quá dài về những điều cơ bản mà tập trung vào các khía cạnh ít được biết đến hơn có khả năng thu hút sự chú ý của ngay cả những chuyên gia cơ sở dữ liệu có kinh nghiệm nhất.
Trong phần đầu tiên này, sau khi giới thiệu nhanh, tôi sẽ xem xét các tác động của tham số hóa đơn giản trên bộ nhớ cache của gói.
Đơn giản hóa tham số
Hầu như luôn tốt hơn nếu tham số hóa rõ ràng thay vì dựa vào máy chủ để làm điều đó. Rõ ràng cho phép bạn kiểm soát hoàn toàn tất cả các khía cạnh của quá trình tham số hóa, bao gồm vị trí các tham số được sử dụng, loại dữ liệu chính xác được sử dụng và khi nào các kế hoạch được sử dụng lại.
Hầu hết các máy khách và trình điều khiển cung cấp các cách cụ thể để sử dụng tham số hóa rõ ràng. Ngoài ra còn có các tùy chọn như sp_executesql
, các thủ tục và chức năng được lưu trữ.
Tôi sẽ không đi sâu vào các vấn đề liên quan của đánh giá tham số hoặc chèn SQL bởi vì mặc dù quan trọng nhưng chúng không phải là trọng tâm của loạt bài này. Tuy nhiên, bạn nên viết mã bằng cả hai cách gần gũi với tâm trí của bạn.
Đối với các ứng dụng cũ hoặc mã của bên thứ ba khác không thể thay đổi dễ dàng, có thể không phải lúc nào cũng thực hiện được tham số hóa rõ ràng. Bạn có thể vượt qua một số trở ngại bằng cách sử dụng hướng dẫn kế hoạch mẫu. Trong mọi trường hợp, đó sẽ là một khối lượng công việc bất thường không chứa ít nhất một số câu lệnh được tham số hóa phía máy chủ.
Shell Plans
Khi SQL Server 2005 giới thiệu Tham số bắt buộc , tham số tự động hiện có tính năng đã được đổi tên thành Tham số đơn giản . Bất chấp sự thay đổi trong thuật ngữ, tham số hóa đơn giản hoạt động giống như tham số hóa tự động luôn làm:SQL Server cố gắng thay thế các giá trị chữ không đổi trong các câu lệnh đặc biệt bằng các dấu tham số. Mục đích là giảm quá trình tổng hợp bằng cách tăng cường tái sử dụng kế hoạch đã lưu trong bộ nhớ cache.
Hãy xem một ví dụ, sử dụng cơ sở dữ liệu Stack Overflow 2010 trên SQL Server 2019 CU 14. Khả năng tương thích của cơ sở dữ liệu được đặt thành 150 và ngưỡng chi phí cho tính song song được đặt thành 50 để tránh song song vào lúc này:
EXECUTE sys.sp_configure @configname = 'show advanced options', @configvalue = 1; RECONFIGURE; GO EXECUTE sys.sp_configure @configname = 'cost threshold for parallelism', @configvalue = 50; RECONFIGURE;
Mã mẫu:
-- Clear the cache of plans for this database ALTER DATABASE SCOPED CONFIGURATION CLEAR PROCEDURE_CACHE; GO SELECT U.DisplayName FROM dbo.Users AS U WHERE U.Reputation = 2521; GO SELECT U.DisplayName FROM dbo.Users AS U WHERE U.Reputation = 2827; GO SELECT U.DisplayName FROM dbo.Users AS U WHERE U.Reputation = 3144; GO SELECT U.DisplayName FROM dbo.Users AS U WHERE U.Reputation = 3151; GO
Các câu lệnh đó có các vị từ chỉ khác nhau về giá trị chữ không đổi của chúng. SQL Server áp dụng thành công tham số hóa đơn giản , dẫn đến một kế hoạch được tham số hóa. Kế hoạch được tham số hóa duy nhất được sử dụng bốn lần như chúng ta có thể thấy bằng cách truy vấn bộ nhớ cache của kế hoạch:
SELECT CP.usecounts, CP.cacheobjtype, CP.objtype, CP.size_in_bytes, ST.[text], QP.query_plan FROM sys.dm_exec_cached_plans AS CP OUTER APPLY sys.dm_exec_sql_text (CP.plan_handle) AS ST OUTER APPLY sys.dm_exec_query_plan (CP.plan_handle) AS QP WHERE ST.[text] NOT LIKE '%dm_exec_cached_plans%' AND ST.[text] LIKE '%DisplayName%Users%' ORDER BY CP.usecounts ASC;
Kết quả cho thấy một Adhoc lập kế hoạch mục nhập bộ nhớ cache cho mỗi câu lệnh gốc và một mục Đã chuẩn bị kế hoạch:
Bốn kế hoạch adhoc và một kế hoạch đã chuẩn bị
A Đã chuẩn bị câu lệnh tương tự như một thủ tục được lưu trữ, với các tham số được suy ra từ các giá trị theo nghĩa đen được tìm thấy trong Adhoc tuyên bố. Tôi đề cập đến điều này như một mô hình tinh thần hữu ích khi nghĩ về quy trình tham số hóa phía máy chủ.
Lưu ý rằng SQL Server lưu vào bộ nhớ đệm cả hai văn bản gốc và dạng tham số hóa. Khi tham số hóa đơn giản thành công, kế hoạch được liên kết với văn bản gốc là Adhoc và không chứa một kế hoạch thực hiện đầy đủ. Thay vào đó, kế hoạch được lưu trong bộ nhớ cache là một shell với rất ít bên cạnh một con trỏ đến thẻ Đã chuẩn bị kế hoạch tham số hóa.
Biểu diễn XML của kế hoạch shell chứa văn bản như:
<ShowPlanXML xmlns="http://schemas.microsoft.com/sqlserver/2004/07/showplan" Version="1.539" Build="15.0.4188.2"> <BatchSequence> <Batch> <Statements> <StmtSimple StatementText="SELECT U.DisplayName
FROM dbo.Users AS U 
WHERE U.Reputation = 3151" StatementId="1" StatementCompId="1" StatementType="SELECT" RetrievedFromCache="true" ParameterizedPlanHandle="0x0600050090C8321CE04B4B079E01000001000000000000000000000000000000000000000000000000000000" ParameterizedText="(@1 smallint)SELECT [U].[DisplayName] FROM [dbo].[Users] [U] WHERE [U].[Reputation]=@1" /> </Statements> </Batch> </BatchSequence> </ShowPlanXML>
Đó là toàn bộ kế hoạch. ParameterizedPlanHandle điểm từ Adhoc bao gồm kế hoạch tham số đầy đủ. Giá trị xử lý giống nhau đối với tất cả bốn kế hoạch shell.
Sơ lược về kế hoạch
Các kế hoạch Shell nhỏ hơn một kế hoạch được biên dịch đầy đủ — 16KB thay vì 40KB trong ví dụ. Điều này vẫn có thể chiếm một lượng lớn bộ nhớ nếu bạn có nhiều câu lệnh sử dụng tham số hóa đơn giản hoặc nhiều giá trị tham số khác nhau. Hầu hết các phiên bản SQL Server không tràn ngập bộ nhớ đến mức chúng có thể lãng phí bộ nhớ như thế này. Các kế hoạch shell được SQL Server coi là dùng một lần, nhưng việc tìm kiếm và loại bỏ chúng sẽ tiêu tốn tài nguyên và có thể trở thành một vấn đề tranh cãi.
Chúng tôi có thể giảm tổng mức tiêu thụ bộ nhớ cho các gói shell bằng cách bật tùy chọn tối ưu hóa cho khối lượng công việc đột xuất.
EXECUTE sys.sp_configure @configname = 'show advanced options', @configvalue = 1; RECONFIGURE; GO EXECUTE sys.sp_configure @configname = 'optimize for ad hoc workloads', @configvalue = 1; RECONFIGURE;
Điều này lưu trữ một sơ khai nhỏ khi lần đầu tiên gặp một câu lệnh đặc biệt thay vì một trình bao. Phần sơ khai đóng vai trò như một dấu trang để máy chủ có thể nhớ rằng nó đã nhìn thấy văn bản câu lệnh chính xác trước đó. Khi gặp cùng một văn bản lần thứ hai, quá trình biên dịch và bộ nhớ đệm sẽ tiến hành như thể tối ưu hóa cho khối lượng công việc đặc biệt không được kích hoạt.
Chạy lại ví dụ với tối ưu hóa cho khối lượng công việc đặc biệt được bật cho thấy ảnh hưởng đến bộ nhớ cache của gói.
Kế hoạch tổng hợp
Không có kế hoạch nào được lưu vào bộ nhớ đệm cho các câu lệnh đặc biệt, chỉ là sơ khai. Không có ParameterizedPlanHandle con trỏ đến thẻ Đã chuẩn bị kế hoạch, mặc dù một kế hoạch được tham số hóa hoàn chỉnh là được lưu vào bộ nhớ đệm.
Chạy các lô thử nghiệm lần thứ hai (mà không xóa bộ nhớ cache của kế hoạch) cho kết quả tương tự như khi tối ưu hóa cho khối lượng công việc đặc biệt chưa được bật — bốn Adhoc kế hoạch shell trỏ đến phần Đã chuẩn bị kế hoạch.
Trước khi tiếp tục, hãy đặt lại tối ưu hóa cho khối lượng công việc đặc biệt cài đặt thành 0:
EXECUTE sys.sp_configure @configname = 'optimize for ad hoc workloads', @configvalue = 0; RECONFIGURE;
Giới hạn kích thước bộ nhớ cache của kế hoạch
Cho dù kế hoạch shell hoặc sơ khai kế hoạch được sử dụng, vẫn có những nhược điểm đối với tất cả những Adhoc này các mục trong bộ nhớ cache. Tôi đã đề cập đến tổng mức sử dụng bộ nhớ, nhưng mỗi bộ nhớ cache của gói cũng có số tối đa trong tổng số các mục nhập. Ngay cả khi tổng mức sử dụng bộ nhớ không phải là vấn đề đáng lo ngại, thì số lượng tuyệt đối có thể là.
Các giới hạn có thể được nâng lên với cờ theo dõi được lập thành văn bản 174 (số lượng mục nhập) và cờ theo dõi 8032 (tổng kích thước). Tùy thuộc vào khối lượng công việc và các nhu cầu bộ nhớ khác, đây có thể không phải là giải pháp tốt nhất. Rốt cuộc, điều đó chỉ có nghĩa là vào bộ nhớ đệm nhiều Adhoc có giá trị thấp hơn kế hoạch, lấy đi bộ nhớ khỏi các nhu cầu khác.
Chỉ lưu vào bộ nhớ đệm Các kế hoạch đã chuẩn bị
Nếu khối lượng công việc hiếm khi phát hành các lô đặc biệt với chính xác cùng một văn bản tuyên bố, vỏ kế hoạch trong bộ nhớ đệm hoặc sơ khai kế hoạch là một sự lãng phí tài nguyên. Nó tiêu tốn bộ nhớ và có thể gây ra tranh cãi khi Kế hoạch SQL bộ nhớ đệm lưu trữ (CACHESTORE_SQLCP
) cần được thu nhỏ để phù hợp với giới hạn đã định cấu hình.
Lý tưởng sẽ là tham số hóa các lô đặc biệt đến, nhưng chỉ lưu vào bộ nhớ cache phiên bản được tham số hóa. Việc này phải trả phí vì các câu lệnh đặc biệt trong tương lai cần phải được tham số hóa trước khi chúng có thể được khớp với kế hoạch được lưu trong bộ nhớ cache được tham số hóa. Mặt khác, dù sao thì điều này cũng đã xảy ra vì chúng tôi đã nêu rõ chính xác các kết quả phù hợp văn bản hiếm khi xảy ra đối với khối lượng công việc mục tiêu.
Đối với khối lượng công việc được hưởng lợi từ tham số hóa đơn giản, nhưng không được hưởng lợi từ bộ nhớ đệm của Adhoc các mục nhập, có một số tùy chọn.
Cờ theo dõi không có tài liệu
Tùy chọn đầu tiên là bật cờ theo dõi không có tài liệu 253. Điều này ngăn chặn bộ nhớ đệm của Adhoc kế hoạch hoàn toàn. Nó không chỉ đơn giản là hạn chế số lượng các kế hoạch như vậy hoặc ngăn chúng “ở lại” trong bộ nhớ cache, như đôi khi đã được đề xuất.
Cờ theo dõi 253 có thể được bật ở cấp phiên — giới hạn ảnh hưởng của nó đối với kết nối đó — hoặc rộng hơn là cờ toàn cầu hoặc cờ khởi động. Nó cũng hoạt động như một gợi ý truy vấn, nhưng việc sử dụng những gợi ý đó ngăn cản việc tham số hóa đơn giản, điều này sẽ phản tác dụng ở đây. Có một phần danh sách những điều ngăn cản việc tham số hóa đơn giản trong Tài liệu Kỹ thuật của Microsoft, Kế hoạch Cache và Biên dịch trong SQL Server 2012.
Với cờ theo dõi 253 hoạt động trước khi lô được biên dịch , chỉ phần Đã chuẩn bị các câu lệnh được lưu vào bộ nhớ đệm:
ALTER DATABASE SCOPED CONFIGURATION CLEAR PROCEDURE_CACHE; GO -- Do not cache ad-hoc plans DBCC TRACEON (253); GO SELECT U.DisplayName FROM dbo.Users AS U WHERE U.Reputation = 2521; GO SELECT U.DisplayName FROM dbo.Users AS U WHERE U.Reputation = 2827; GO SELECT U.DisplayName FROM dbo.Users AS U WHERE U.Reputation = 3144; GO SELECT U.DisplayName FROM dbo.Users AS U WHERE U.Reputation = 3151; GO -- Cache ad-hoc plans again DBCC TRACEOFF (253); GO
Truy vấn bộ nhớ cache kế hoạch chỉ xác nhận thông tin Đã chuẩn bị câu lệnh được lưu vào bộ nhớ đệm và sử dụng lại.
Chỉ câu lệnh đã chuẩn bị được lưu vào bộ nhớ đệm
Lô không thể lưu trữ
Tùy chọn thứ hai là bao gồm một câu lệnh đánh dấu toàn bộ lô là không thể lưu vào bộ nhớ cache . Các câu lệnh phù hợp thường liên quan đến bảo mật hoặc theo một cách nào đó nhạy cảm.
Điều này nghe có vẻ không thực tế, nhưng có một vài biện pháp giảm thiểu. Đầu tiên, câu lệnh nhạy cảm không cần được thực thi — nó chỉ cần có hiện tại . Khi điều kiện đó được đáp ứng, người dùng chạy lô thậm chí không cần quyền để thực hiện câu lệnh nhạy cảm. Lưu ý cẩn thận, hiệu ứng được giới hạn trong lô có chứa câu lệnh nhạy cảm.
Hai câu lệnh có độ nhạy phù hợp và cách sử dụng ví dụ được hiển thị bên dưới (với các câu lệnh kiểm tra hiện đang ở trong một lô duy nhất):
ALTER DATABASE SCOPED CONFIGURATION CLEAR PROCEDURE_CACHE; GO -- Prevent caching of all statements in this batch. -- Neither KEY nor CERTIFICATE need to exist. -- No special permissions are needed. -- GOTO is used to ensure the statements are not executed. GOTO Start OPEN SYMMETRIC KEY Banana DECRYPTION BY CERTIFICATE Banana; Start: /* Another way to achieve the same effect without GOTO IF 1 = 0 BEGIN CREATE APPLICATION ROLE Banana WITH PASSWORD = ''; END; */ SELECT U.DisplayName FROM dbo.Users AS U WHERE U.Reputation = 2521; SELECT U.DisplayName FROM dbo.Users AS U WHERE U.Reputation = 2827; SELECT U.DisplayName FROM dbo.Users AS U WHERE U.Reputation = 3144; SELECT U.DisplayName FROM dbo.Users AS U WHERE U.Reputation = 3151; GO
Sự kiện Đã chuẩn bị kế hoạch được tạo bởi tham số hóa đơn giản vẫn được lưu vào bộ nhớ cache và được sử dụng lại mặc dù lô chính được đánh dấu là không thể lưu vào bộ nhớ cache.
Chỉ câu lệnh đã chuẩn bị được lưu vào bộ nhớ đệm
Không giải pháp nào là lý tưởng, nhưng cho đến khi Microsoft cung cấp giải pháp được tài liệu hóa và hỗ trợ cho vấn đề này, chúng là những lựa chọn tốt nhất mà tôi biết.
Kết thúc Phần 1
Có rất nhiều cơ sở để đề cập đến chủ đề này. Phần hai sẽ bao gồm các kiểu dữ liệu được chỉ định khi tham số hóa đơn giản được tuyển dụng.