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

SQL Server Internals:Lập kế hoạch Caching Pt. II - Biên soạn lại các kế hoạch

Đây là một phần của loạt bài SQL Server Internals Plan Caching. Hãy nhớ đọc bài đăng đầu tiên của Kalen về chủ đề này.

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ử

Trong bài viết trước của tôi , Tôi đã nói về chẩn đoán máy chủ SQL, bao gồm các tùy chọn khác nhau mà Máy chủ SQL có để sử dụng lại kế hoạch truy vấn. Chúng tôi đã xem xét ba loại kế hoạch truy vấn:adhoc, chuẩn bị và thủ tục. Tôi đã kết thúc cuộc thảo luận bằng cách xem xét việc sử dụng lại một kế hoạch không phù hợp, điều này có thể xảy ra khi SQL Server áp dụng tính năng dò tìm tham số trong các tình huống sai. Nếu một kế hoạch dựa trên một giá trị ban đầu khiến trình tối ưu hóa tạo ra một kế hoạch phù hợp với giá trị đó và sau đó kế hoạch tương tự được sử dụng cho một giá trị khác, thì kế hoạch đó có thể không còn là tối ưu nữa.

Vì vậy, chúng ta có thể làm gì khi đánh hơi tham số là một vấn đề? Chúng tôi có thể buộc SQL Server đưa ra một kế hoạch mới. Thông thường, chúng tôi gọi hành động đưa ra một kế hoạch mới là "biên dịch lại", nhưng có lẽ nó nên được gọi là "tối ưu hóa lại". Tuy nhiên, hầu hết mọi người sử dụng thuật ngữ 'biên dịch lại', vì vậy đó là những gì tôi sẽ sử dụng ở đây.

Nếu việc sử dụng tính năng đánh hơi tham số không phù hợp là một vấn đề, một giải pháp đơn giản là chỉ cần yêu cầu SQL Server đưa ra một kế hoạch mới. Đối với các câu lệnh riêng lẻ, chẳng hạn như với các gói CHUẨN BỊ đã được tự động xác định, chúng tôi có thể thêm gợi ý RECOMPILE vào một truy vấn. Sử dụng FORCED được tham số hóa (đã thảo luận trong bài trước), truy vấn này sẽ được tham số hóa.

SELECT * FROM dbo.newsales 
WHERE SalesOrderID < @num;

Nếu chúng tôi muốn đảm bảo rằng chúng tôi nhận được một kế hoạch mới mỗi khi chúng tôi chạy truy vấn này, với các giá trị tiềm năng khác nhau rất lớn cho @num, chúng tôi có thể thêm gợi ý RECOMPILE như được hiển thị:

SELECT * FROM dbo.newsales
  WHERE SalesOrderID < @num
OPTION (RECOMPILE);

Đối với các thủ tục được lưu trữ, chúng tôi có ba tùy chọn. Đầu tiên, chúng tôi có thể chắc chắn liệu việc biên dịch lại có thực sự giúp ích cho hiệu suất hay không bằng cách thực hiện quy trình với tùy chọn RECOMPILE:

EXEC get_sales_range 66666 WITH RECOMPILE;

Tùy chọn này sẽ tạo ra một kế hoạch mới chỉ cho một lần thực thi này. Nó sẽ không được lưu và chắc chắn sẽ không được sử dụng lại. Giá trị usecount được hiển thị trong sp_cacheobjects (được mô tả trong bài trước) cho quy trình sẽ không tăng vì gói ban đầu không được sử dụng lại.

Thứ hai, nếu chúng tôi thấy rằng việc thực thi WITH RECOMPILE hữu ích, chúng tôi có thể xem xét tạo lại quy trình với tùy chọn RECOMPILE, trong trường hợp đó, nó sẽ không bao giờ sử dụng lại kế hoạch và thủ tục sẽ không hiển thị trong bộ nhớ cache của kế hoạch.

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

Đối với thủ tục nhỏ đơn giản của tôi, sử dụng tùy chọn WITH RECOMPILE cho toàn bộ quy trình có thể có ý nghĩa. Nhưng nếu quy trình phức tạp hơn, việc biên dịch lại toàn bộ quy trình có thể không hợp lý vì một câu lệnh gây ra sự cố. Vì vậy, tùy chọn thứ ba là sử dụng gợi ý RECOMPILE cho một câu lệnh trong quy trình, vì vậy nó trông giống như sau:

DROP PROC IF EXISTS get_sales_range;
GO
CREATE PROC get_sales_range
   @num int
AS
    SELECT * FROM dbo.newsales
    WHERE SalesOrderID < @num
    OPTION (RECOMPILE);
GO

Việc sử dụng một trong các tùy chọn RECOMPILE này có thể buộc SQL Server đưa ra một kế hoạch mới theo yêu cầu của bạn. Bây giờ, chúng ta sẽ xem xét thời điểm chẩn đoán SQL Server của bạn đưa ra một gói mới khi bạn không yêu cầu, tức là khi nào thì quá trình biên dịch lại tự động của một gói hiện có xảy ra?


Tự động biên dịch lại kế hoạch xảy ra trong hai loại tình huống:

  • Đầu tiên, nếu trình tối ưu hóa xác định rằng kế hoạch hiện tại không còn đúng nữa, thường là do thay đổi trong định nghĩa đối tượng, nó sẽ cần đưa ra một kế hoạch mới. Ví dụ:nếu bạn có một kế hoạch cho một truy vấn chọn từ TableA và sau đó bạn thả một số cột hoặc thay đổi kiểu dữ liệu của các cột trong TableA, SQL Server sẽ biên dịch lại truy vấn để đưa ra một kế hoạch phản ánh những thay đổi DDL.
  • Tình huống thứ hai xảy ra quá trình biên dịch lại tự động là khi SQL Server xác định rằng kế hoạch có thể không còn tối ưu nữa, do sự thay đổi trong thống kê. Trong hầu hết các trường hợp, nếu thống kê về bất kỳ cột hoặc chỉ mục nào đã được cập nhật kể từ lần cuối cùng kế hoạch được biên soạn, nó sẽ được biên dịch lại. Nhưng điều này dẫn đến một câu hỏi khác. Khi nào các số liệu thống kê được cập nhật? Thống kê có thể được cập nhật tự động khi đủ hàng trong các cột có liên quan đã thay đổi. Bao nhiêu là đủ? Chúng tôi nói về điều đó ngay sau đây.

Theo mặc định, SQL Server sẽ tự động cập nhật thống kê do tùy chọn cơ sở dữ liệu được BẬT theo mặc định. Nhưng nếu bạn là chủ sở hữu cơ sở dữ liệu (hoặc SQL ‘sa’, xuất hiện dưới dạng chủ sở hữu trong mọi cơ sở dữ liệu), bạn có thể thay đổi các tùy chọn. Một trong các tùy chọn được gọi là AUTO_UPDATE_STATISTICS và một tùy chọn khác được gọi là AUTO_UPDATE_STATISTICS_ASYNC. Tùy chọn AUTO_UPDATE_STATISTICS được BẬT trong cơ sở dữ liệu tempdb, vì vậy mọi cơ sở dữ liệu mới kế thừa tùy chọn này. Khi tùy chọn này BẬT và công cụ thực thi truy vấn phát hiện các thay đổi đối với đủ số hàng trong khi truy vấn đang được xử lý, việc thực thi sẽ tạm dừng trong khi thống kê được cập nhật và sau đó truy vấn được biên dịch lại. Tùy chọn khác, AUTO_UPDATE_STATISTICS_ASYNC, có thể ít ảnh hưởng hơn đến thời gian thực hiện truy vấn vì quá trình thực thi không tạm dừng, với chi phí sử dụng một kế hoạch tối ưu có thể có. Với tùy chọn thứ hai, nếu công cụ thực thi phát hiện cần cập nhật thống kê, một luồng nền sẽ được kích hoạt để thực hiện cập nhật và luồng chính tiếp tục thực hiện truy vấn với thống kê ban đầu và kế hoạch ban đầu. Truy vấn tiếp theo truy cập vào các bảng bị ảnh hưởng và xem thống kê được cập nhật sẽ biên dịch lại truy vấn, nhưng nó sẽ không tạm dừng và cập nhật thống kê khi đang thực thi.

Có một số tình huống khác cũng như một số gợi ý truy vấn kiểm soát việc kế hoạch có được biên dịch lại hay không, vì vậy tôi sẽ cho bạn xem một sơ đồ. Tôi sẽ chia sẻ với bạn một lưu đồ mà tôi đã tạo cho các lớp đào tạo của mình về nội bộ SQL Server.

Mũi tên là nơi SQL Server bắt đầu xử lý lô của bạn. Trước tiên, nó sẽ kiểm tra xem liệu đã có kế hoạch cho lô của bạn trong bộ nhớ cache hay chưa và nếu câu trả lời là KHÔNG, hãy làm theo mũi tên bên phải và soạn một kế hoạch. Kế hoạch được đưa vào bộ nhớ cache và sau đó SQL Server bắt đầu lại. Có, kế hoạch sẽ được lưu trong bộ nhớ cache lần này, vì vậy kế hoạch đi theo mũi tên hướng xuống và hỏi xem gợi ý có tên KEEP PLAN đã được sử dụng hay chưa. Nếu CÓ, SQL Server bắt đầu thực thi kế hoạch ngay lập tức và không thực hiện bất kỳ kiểm tra nào nữa.

Câu hỏi tiếp theo là liệu có bất kỳ thay đổi DDL nào đã được thực hiện hay không. Nếu không, nó hỏi về một số tình huống khác mà tôi sẽ không thể nói trong bài viết này. Trên thực tế, tôi thực sự sẽ không xem qua mọi lựa chọn ở đây. Tôi sẽ giao việc đó cho bạn. Nhưng nếu bạn có bất kỳ câu hỏi hoặc thắc mắc nào, hãy hỏi họ trong phần nhận xét tại đây hoặc tweet cho tôi tại @sqlqueen. Tôi sẽ chỉ ra câu hỏi ở ngoài cùng bên phải:AUTO_STATS_ASYNC có BẬT không? Ở đây, bạn có thể thấy rằng nếu câu trả lời là CÓ, thì có hai hành động. Một nhánh chỉ bắt đầu thực thi với kế hoạch hiện có và nhánh kia là chuỗi nền cập nhật thống kê nhưng sau đó không thực hiện bất kỳ điều gì khác. Truy vấn tiếp theo sẽ gặp hộp quyết định ở giữa “Có sẵn số liệu thống kê mới không” và phải trả lời CÓ, vì vậy truy vấn sẽ được biên dịch lại.

Điều duy nhất tôi sẽ nói đến là câu hỏi “Có số liệu thống kê nào cũ không?” Điều này về cơ bản có nghĩa là số liệu thống kê đã lỗi thời vì quá nhiều thay đổi đã được thực hiện. Vì vậy, bây giờ chúng ta có thể nói về số lượng là quá nhiều.

Mặc dù có các giá trị khác nhau được sử dụng cho các bảng rất nhỏ, đối với bất kỳ bảng nào có hơn 500 hàng trong đó, trước SQL Server 2016, thống kê sẽ được coi là 'cũ' khi số lượng thay đổi đối với cột mà thống kê dựa trên 20 % số hàng trong bảng. Vì vậy, đối với một bảng gồm 1000 hàng, điều này có thể có nghĩa là 200 lần chèn, 200 lần cập nhật hoặc 200 lần xóa. Nó có thể là 200 hàng thay đổi hoặc 5 hàng được cập nhật 40 lần mỗi hàng. SQL Server thậm chí còn cung cấp cho chúng ta một chức năng báo cáo có bao nhiêu thay đổi đã được thực hiện. Bạn sẽ cần phải tra cứu số stats_id cho thống kê mà bạn quan tâm, sẽ là index_id nếu thống kê thuộc về một chỉ mục. Stats_id có thể được tìm thấy trong dạng xem được gọi là sys.stats. Trong bảng bán tin của tôi, tôi sử dụng truy vấn này để thấy rằng stats_id cho chỉ mục trên cột Tổng số phụ là 3.

SELECT name, stats_id FROM sys.stats
WHERE object_id = object_id('newsales');

Sau đó, tôi có thể sử dụng giá trị đó để xem số lượng thay đổi. Trước tiên, hãy để tôi cập nhật một số hàng:

UPDATE newsales
SET SubTotal = SubTotal * 0.9
WHERE SalesOrderID < 45200
(1541 hàng bị ảnh hưởng)

SELECT * FROM sys.dm_db_stats_properties(object_id('newsales'), 3);  

Thực tế, 20% là một con số LỚN. Và đối với nhiều bảng, các truy vấn có thể được hưởng lợi từ thống kê được cập nhật với ít hơn 20% số hàng được cập nhật. Bắt đầu từ 2008R2 SP1, SQL Server đã bao gồm một Traceflag mà bạn có thể sử dụng để thay đổi số hàng thành một thang trượt, như được hiển thị trong biểu đồ sau:

Bắt đầu từ SQL Server 2016, thuật toán mới với thang trượt này được sử dụng theo mặc định, miễn là bạn ở mức tương thích 130 trở lên.

Hầu hết các bản biên dịch lại tự động của các kế hoạch truy vấn là do những thay đổi trong số liệu thống kê. Nhưng như tôi đã đề cập ở trên, đó không phải là lý do duy nhất để biên dịch lại. Nhưng vì đây là cách phổ biến nhất, nên có thể rất hữu ích nếu bạn nhận biết được thời điểm và cách thức các thống kê được cập nhật và đảm bảo rằng số liệu thống kê trên các bảng quan trọng của bạn được cập nhật thường xuyên để đảm bảo bạn có được kế hoạch tốt nhất!

Tự động phân tích dữ liệu hiệu suất để thực hiện chẩn đoán máy chủ SQL nhằm giải quyết các sự cố một cách nhanh chóng và xác định các máy chủ bắt nguồn từ việc suy giảm hiệu suất. Bắt đầu sử dụng Spotlight Cloud ngay hôm nay:


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Thành thạo việc sử dụng danh sách dừng với tìm kiếm toàn văn bản trên SQL Server (FTS)

  2. SSMS hiện đi kèm với Azure Data Studio

  3. 3 cách trả về tất cả các bảng KHÔNG có khóa chính trong SQL Server

  4. Làm thế nào để kiểm tra xem một Ràng buộc tồn tại trong máy chủ Sql?

  5. Loại SQL chính xác để lưu trữ .Net Timespan có giá trị> 24:00:00 là gì?