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

SQL Server Internals:Lập kế hoạch Caching Pt. I - Tái sử dụng các kế hoạch

SQL Server đã có hơn 30 năm và tôi đã làm việc với SQL Server gần như lâu rồi. Tôi đã thấy rất nhiều thay đổi trong nhiều năm (và nhiều thập kỷ!) Và các phiên bản của sản phẩm đáng kinh ngạc này. Trong các bài đăng này, tôi sẽ chia sẻ với bạn cách tôi xem xét một số tính năng hoặc khía cạnh của SQL Server, đôi khi cùng với một chút quan điểm lịch sử.

Xem các blog gần đây của Kalen về Nhà điều hành có vấn đề tại đây.

Kế hoạch chẩn đoán máy chủ SQL có thể tốn kém để tạo, vì trình tối ưu hóa truy vấn phải có khả năng tìm ra kế hoạch tốt cho bất kỳ truy vấn pháp lý nào được gửi. Trình tối ưu hóa đánh giá nhiều thứ tự tham gia, nhiều chỉ mục. và các loại thuật toán nối và nhóm khác nhau, tùy thuộc vào truy vấn của bạn và các bảng có liên quan. Nếu cùng một truy vấn được chạy lại, SQL Server có thể tiết kiệm nhiều tài nguyên bằng cách sử dụng lại một kế hoạch hiện có. Nhưng không phải lúc nào bạn cũng có thể sử dụng lại một kế hoạch hiện có và không phải lúc nào làm như vậy cũng là điều tốt. Trong hai bài viết tiếp theo, chúng ta sẽ xem xét khi nào một kế hoạch được sử dụng lại và khi nào nó được biên dịch lại.

Trước tiên, chúng ta sẽ xem xét các hương vị khác nhau của các gói và chế độ xem siêu dữ liệu mà tôi sử dụng thường xuyên nhất để xem những gì có trong bộ nhớ cache gói của tôi. Tôi đã viết một quan điểm của riêng tôi cung cấp thông tin mà tôi thấy hữu ích nhất thường xuyên nhất. SQL Server lưu vào bộ đệm sáu loại kế hoạch truy vấn khác nhau, nhưng chỉ có hai loại thường được sử dụng để điều chỉnh bộ đệm kế hoạch. Đây là KẾ HOẠCH TỔNG HỢP và CÂU CHUYỆN KẾ HOẠCH TỔNG HỢP. Chế độ xem của tôi lọc ra tất cả trừ hai loại đối tượng bộ nhớ cache này. KẾ HOẠCH TỔ HỢP có ba loại:AD HOC, PREPARED và PROC. Tôi sẽ nhận xét về cả ba loại.

Ngay cả khi chúng ta chỉ đang xem xét các KẾ HOẠCH ĐÃ LINH KIỆN, vẫn có rất nhiều kế hoạch trong bộ nhớ cache thường cần được bỏ qua, vì chúng được tạo bởi chính SQL Server. Chúng bao gồm các kế hoạch tìm kiếm các chỉ mục tìm kiếm toàn văn hoặc dòng lọc hoặc các truy vấn nội bộ hoạt động với OLTP trong bộ nhớ. Vì vậy, chế độ xem của tôi thêm các bộ lọc để thử và loại bỏ hầu hết các kế hoạch mà tôi không quan tâm. Bạn có thể tải xuống tập lệnh để tạo chế độ xem này, có tên là sp_cacheobjects , từ đây.

Ngay cả với tất cả các bộ lọc mà chế độ xem của tôi sử dụng, vẫn có một số truy vấn nội bộ của SQL Server trong bộ nhớ cache; Tôi thường xóa bộ nhớ cache của kế hoạch thường xuyên khi thực hiện thử nghiệm trong lĩnh vực này. Cách đơn giản nhất để xóa TẤT CẢ các kế hoạch khỏi bộ nhớ cache là sử dụng lệnh:DBCC FREEPROCCACHE.

Các kế hoạch được tổng hợp của Adhoc

Loại kế hoạch đơn giản nhất là Adhoc. Điều này được sử dụng cho các truy vấn cơ bản không phù hợp với một danh mục khác. Nếu bạn đã tải xuống tập lệnh của tôi và tạo chế độ xem sp_cacheobjects của tôi, bạn có thể chạy như sau. Bất kỳ phiên bản nào của cơ sở dữ liệu AdventureWorks đều hoạt động. Tập lệnh này tạo một bản sao của một bảng và xây dựng một vài chỉ mục duy nhất trên đó. Nó cũng mát xa số lượng SubTotal để loại bỏ bất kỳ chữ số thập phân nào.

USE AdventureWorks2016;
GO
DROP TABLE IF EXISTS newsales;
GO
-- Make a copy of the Sales.SalesOrderHeader table
SELECT * INTO dbo.newsales
FROM Sales.SalesOrderHeader;
GO
UPDATE dbo.newsales
SET SubTotal = cast(cast(SubTotal as int) as money);
GO
CREATE UNIQUE index newsales_ident
    ON newsales(SalesOrderID);
GO
CREATE INDEX IX_Sales_SubTotal ON newsales(SubTotal);
GO
-- Adhoc query plan reuse
DBCC FREEPROCCACHE;
GO
-- adhoc query
SELECT * FROM dbo.newsales
WHERE SubTotal = 4;
GO
SELECT * FROM sp_cacheobjects;
GO

Trong đầu ra của tôi, bạn sẽ thấy hai kế hoạch Adhoc. Một dành cho câu lệnh SELECT từ newsales và bảng còn lại dành cho SELECT từ sp_cacheobjects của tôi lượt xem. Bởi vì kế hoạch được lưu trong bộ nhớ cache, nếu truy vấn EXACT tương tự được chạy lại, thì có thể sử dụng lại cùng một kế hoạch và bạn sẽ thấy tài khoản sử dụng gia tăng giá trị. Tuy nhiên, có một nhược điểm. Để một kế hoạch Adhoc được sử dụng lại, chuỗi SQL phải hoàn toàn giống nhau. Nếu bạn thay đổi bất kỳ ký tự nào trong SQL, truy vấn sẽ không được nhận dạng là cùng một truy vấn và một kế hoạch mới sẽ được tạo. Nếu tôi thậm chí thêm khoảng trắng, bao gồm nhận xét hoặc ngắt dòng mới, thì đó không phải là cùng một chuỗi. Nếu tôi thay đổi trường hợp, điều đó có nghĩa là có các giá trị mã ASCII khác nhau, do đó không phải là cùng một chuỗi.

Bạn có thể tự mình thử điều này bằng cách chạy các biến thể khác nhau của câu lệnh SELECT đầu tiên của tôi từ newsales bàn. Bạn sẽ thấy một hàng khác nhau trong bộ nhớ cache cho mỗi hàng. Sau khi tôi chạy một số biến thể – thay đổi số tôi đang tìm kiếm, thay đổi trường hợp, thêm nhận xét và một dòng mới, tôi thấy thông tin sau trong bộ nhớ cache. SELECT từ chế độ xem của tôi đang được sử dụng lại, nhưng mọi thứ khác đều có số lượng sử dụng giá trị của 1.

Một yêu cầu bổ sung để tái sử dụng kế hoạch truy vấn Adhoc là phiên đang chạy truy vấn phải có cùng các tùy chọn SET có hiệu lực . Có một cột khác trong đầu ra mà bạn có thể thấy ở bên phải của văn bản truy vấn, được gọi là SETOPTS. Đây là một chuỗi bit với một bit cho mỗi tùy chọn SET có liên quan. Nếu bạn thay đổi một trong các tùy chọn, chẳng hạn như ĐẶT ANSI_NULLS TẮT, chuỗi bit sẽ thay đổi và không thể sử dụng lại cùng kế hoạch với chuỗi bit ban đầu.

Các kế hoạch tổng hợp đã chuẩn bị

Loại thứ hai của kế hoạch đã biên dịch được lưu trong bộ nhớ cache là kế hoạch ĐÃ CHUẨN BỊ. Nếu truy vấn của bạn đáp ứng một số yêu cầu nhất định. Nó thực sự có thể được tham số hóa tự động. Nó hiển thị trong siêu dữ liệu là ĐÃ CHUẨN BỊ và chuỗi SQL hiển thị một điểm đánh dấu tham số. Đây là một ví dụ:

Kế hoạch CHUẨN BỊ hiển thị điểm đánh dấu tham số là @ 1 và không bao gồm giá trị thực. Lưu ý rằng có một hàng dành cho truy vấn ADHOC với giá trị thực là 5555, nhưng đó thực sự chỉ là ‘shell’ của truy vấn thực. Nó không lưu vào bộ nhớ cache toàn bộ kế hoạch mà chỉ truy vấn và một số chi tiết nhận dạng, để giúp bộ xử lý truy vấn tìm thấy kế hoạch được tham số hóa trong bộ nhớ cache. Lưu ý kích thước ( trang được sử dụng ) nhỏ hơn nhiều so với gói CHUẨN BỊ.

Chế độ tham số hóa mặc định, được gọi là tham số hóa SIMPLE, cực kỳ nghiêm ngặt về những kế hoạch nào có thể được tham số hóa. Nó thực sự chỉ là truy vấn đơn giản nhất có thể tham số hóa theo mặc định. Các truy vấn có chứa JOIN, GROUP BY, OR và nhiều cấu trúc truy vấn tương đối phổ biến khác ngăn không cho truy vấn được tham số hóa. Ngoài việc không có bất kỳ cấu trúc nào trong số này, điều quan trọng nhất đối với tham số hóa ĐƠN GIẢN là truy vấn AN TOÀN. Điều này có nghĩa là chỉ có một kế hoạch khả thi bất kể giá trị nào được truyền cho bất kỳ tham số nào. (Tất nhiên, truy vấn không có bất kỳ tham số nào cũng có thể AN TOÀN.) Truy vấn của tôi đang tìm kiếm kết hợp chính xác trên cột SalesOrderID , có một chỉ mục duy nhất trên đó. Vì vậy, chỉ mục không phân biệt hiện có có thể được sử dụng để tìm bất kỳ hàng nào phù hợp. Bất kể tôi sử dụng giá trị nào, 55555 hay thứ gì khác, sẽ không bao giờ có nhiều hơn một hàng, điều đó có nghĩa là kế hoạch sẽ vẫn tốt.

Trong ví dụ về kế hoạch truy vấn Adhoc của tôi, tôi đang tìm kiếm các giá trị phù hợp cho SubTotal . Một số Tổng số phụ các giá trị xảy ra một vài lần hoặc hoàn toàn không xảy ra, vì vậy một chỉ mục không phân tán sẽ là tốt. Nhưng các giá trị khác có thể xuất hiện nhiều lần, vì vậy chỉ mục sẽ KHÔNG hữu ích. Do đó, kế hoạch truy vấn không AN TOÀN và truy vấn không thể được tham số hóa. Đó là lý do tại sao chúng tôi thấy kế hoạch Adhoc cho ví dụ đầu tiên của tôi.

NẾU bạn có các truy vấn với JOIN hoặc các cấu trúc không được phép khác, bạn có thể yêu cầu SQL Server tích cực hơn trong việc tham số hóa bằng cách thay đổi tùy chọn cơ sở dữ liệu:

ALTER DATABASE AdventureWorks2016 SET parameterization FORCED;
GO

Đặt cơ sở dữ liệu của bạn thành tham số FORCED có nghĩa là SQL Server sẽ tham số nhiều hơn nhiều truy vấn, bao gồm những truy vấn có JOIN, GROUP BY, OR, v.v. Nhưng cũng có nghĩa là SQL Server có thể tham số hóa một truy vấn không AN TOÀN. Nó có thể đưa ra một kế hoạch tốt khi chỉ một vài hàng được trả về, và sau đó sử dụng lại kế hoạch khi nhiều hàng được trả về. Điều này có thể dẫn đến hiệu suất rất thấp.

Một lựa chọn cuối cùng cho một kế hoạch đã chuẩn bị là khi bạn chuẩn bị một cách rõ ràng một kế hoạch. Hành vi này thường được gọi thông qua ứng dụng có SQLPrepare SQLExecute API. Bạn chỉ định truy vấn là gì với các dấu tham số, bạn chỉ định các kiểu dữ liệu và bạn chỉ định các giá trị cụ thể để sử dụng. Sau đó có thể chạy lại cùng một truy vấn với các giá trị cụ thể khác nhau và kế hoạch hiện có sẽ được sử dụng. Mặc dù việc sử dụng các kế hoạch được chuẩn bị rõ ràng có thể áp dụng cho những trường hợp SQL Server không tham số hóa và bạn muốn điều đó, nó không ngăn được SQL Server sử dụng một kế hoạch KHÔNG tốt cho các tham số tiếp theo. Bạn cần kiểm tra các truy vấn của mình với nhiều giá trị đầu vào khác nhau và đảm bảo rằng bạn nhận được hiệu suất mong đợi nếu và khi một kế hoạch được sử dụng lại.

Siêu dữ liệu (ví dụ: sp_cacheobjects của tôi xem) chỉ hiển thị CHUẨN BỊ cho cả ba loại kế hoạch:tự động lấy thông số FORCED và ĐƠN GIẢN và tham số EXPLICIT.

Kế hoạch tổng hợp Proc

Loại đối tượng cuối cùng giá trị cho Kế hoạch đã Biên soạn là cho một thủ tục được lưu trữ, được hiển thị dưới dạng Proc. Khi có thể, các thủ tục được lưu trữ là lựa chọn tốt nhất cho mã có thể sử dụng lại, do tính dễ quản lý của chúng từ chính máy chủ, nhưng điều đó không có nghĩa là chúng được đảm bảo luôn cung cấp hiệu suất tốt nhất. Cũng giống như việc sử dụng tùy chọn tham số FORCED (và cả tham số hóa rõ ràng), các thủ tục được lưu trữ sử dụng "tham số đánh hơi". Điều này có nghĩa là giá trị tham số đầu tiên được truyền vào xác định kế hoạch. Nếu các lần thực thi tiếp theo hoạt động tốt với cùng một kế hoạch, thì việc đánh hơi tham số không phải là vấn đề và thực sự có thể có lợi vì nó giúp chúng ta tiết kiệm chi phí biên dịch lại và mở lại. Tuy nhiên, nếu các lần thực thi tiếp theo với các giá trị khác nhau không sử dụng kế hoạch ban đầu, thì chúng tôi có vấn đề. Tôi sẽ chỉ cho bạn một ví dụ về việc đánh giá thông số gây ra sự cố

Tôi sẽ tạo một quy trình được lưu trữ dựa trên bán tin bảng chúng tôi đã sử dụng trước đó. Quy trình sẽ có một truy vấn duy nhất, lọc dựa trên SalesOrderID , trên đó chúng tôi đã xây dựng một chỉ mục không phân biệt. Truy vấn sẽ dựa trên một bất đẳng thức, vì vậy đối với một số giá trị, truy vấn có thể trả về chỉ một vài hàng và sử dụng chỉ mục và đối với các giá trị khác, truy vấn có thể trả về RẤT NHIỀU hàng. Nói cách khác, truy vấn không AN TOÀN.

USE AdventureWorks2016;
GO
DROP PROC IF EXISTS get_sales_range;
GO
CREATE PROC get_sales_range
   @num int
AS
    SELECT * FROM dbo.newsales
    WHERE SalesOrderID < @num;
GO

Tôi sẽ sử dụng tùy chọn SET STATISTICS IO ON để xem khối lượng công việc đang được thực hiện khi quy trình được thực thi. Đầu tiên, tôi sẽ thực thi nó với một tham số chỉ trả về một vài hàng:

SET STATISTICS IO ON
GO
EXEC get_sales_range 43700;
GO

Giá trị STATISTICS IO báo cáo rằng phải mất 43 lần đọc logic để trả về 41 hàng. Điều này là bình thường đối với một chỉ số không phân biệt. Bây giờ chúng ta thực thi lại thủ tục với giá trị lớn hơn nhiều.

EXEC get_sales_range 66666;
GO
SELECT * FROM sp_cacheobjects;
GO
This time, we see that SQL Server used a whole lot more reads:

Trên thực tế, quá trình quét bảng trên bán báo bảng chỉ có 843 lần đọc, vì vậy đây là hiệu suất kém hơn nhiều so với quét bảng. sp_cacheobjects chế độ xem cho chúng ta thấy rằng kế hoạch PROC đã được sử dụng lại cho lần thực thi thứ hai này. Đây là một ví dụ về thời điểm đánh giá tham số KHÔNG phải là điều tốt.

Vì vậy, chúng ta có thể làm gì khi đánh hơi tham số là một vấn đề? Trong bài đăng tiếp theo, tôi sẽ cho bạn biết khi nào SQL Server đưa ra một kế hoạch mới và không sử dụng lại những kế hoạch cũ. Chúng tôi sẽ xem xét cách bạn có thể buộc (hoặc khuyến khích) biên dịch lại và chúng tôi cũng sẽ xem khi nào Máy chủ SQL tự động biên dịch lại các truy vấn của bạn.

Spotlight Cloud có thể cách mạng hóa việc giám sát hiệu suất của bạn và chẩn đoán máy chủ SQL. Bắt đầu với bản dùng thử miễn phí của bạn bằng liên kết bên dưới:


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Trình nghe thay đổi cơ sở dữ liệu SQL Server C #

  2. Cách bật Ràng buộc KIỂM TRA trong SQL Server (Ví dụ T-SQL)

  3. Làm cách nào chúng ta có thể xem phần thân của thủ tục được lưu trữ được mã hóa trong SSMS?

  4. 2 cách tạo bảng nếu nó không tồn tại trong SQL Server

  5. Làm thế nào để thay thế nhiều ký tự trong SQL?