本文屬於Azure SQL DB/DW系列
上一文:Azure SQL DB/DW 系列(5)——Query Store案例(2)——計劃迴歸
本文演示如何用Query Store查看等待信息
前言
關於等待信息的查看和使用方式有很多種,本文用全新的方法也就是Query Store來查看等待信息。
我們知道,等待信息幾乎可以說是常規應對性能問題甚至其他異常時的首要切入點。其實回顧過去的等待信息,它本身也在不停發展,比如sys.dm_os_wait_statistics和sys.dm_os_waiting_tasks這兩個過去非常重要的DMV之外,從2016開始又引入了sys.dm_exec_session_wait_stats,用於提供關於正在活動的會話的等待信息。
從SQL 2016 SP1開始,等待信息也開始存在於實際執行計劃中。但是執行計劃的內容通常還是比較難準確有效地捕獲的,所以我們可以使用Query Store,上一文也演示過關於執行計劃在Query Store中的使用,所以我們可以用類似的方式來獲取等待信息。
環境準備
這次使用WideWorldImporters作爲測試,如果像我現在使用Linux上的SQL Server,可以參考我的文章裏面的方法下載:SQL Server On Linux(3)——SQL Server 2019 For Linux 下載並部署示例數據庫,下面是我用的下載文件命令:
wget -O /tmp/WideWorldImporters-Full.bak "https://github.com/Microsoft/sql-server-samples/releases/download/wide-world-importers-v1.0/WideWorldImporters-Full.bak"
下載完成之後,就還原到我的數據庫中,過程就不演示了。下面對這個庫修改兼容級別到2019(150)並開啓Query Store,然後做簡單的配置,如果要反覆實驗,可以用腳本中的第四部分來清空Query Store:
USE [master]
GO
ALTER DATABASE [WideWorldImporters] SET COMPATIBILITY_LEVEL = 150
GO
ALTER DATABASE [WideWorldImporters] SET QUERY_STORE = ON;
GO
ALTER DATABASE [WideWorldImporters] SET QUERY_STORE
(
OPERATION_MODE = READ_WRITE
);
GO
--清空Query Store
ALTER DATABASE [WideWorldImporters] SET QUERY_STORE CLEAR;
GO
然後創建一個存儲過程,OPTION (QUERYTRACEON 8649)代表着強制執行並行運行:
use WideWorldImporters
GO
CREATE OR ALTER PROCEDURE [Sales].[OrderInfo]
AS
BEGIN
WHILE 1=1
BEGIN
SELECT *
FROM Sales.OrderLines ol
INNER JOIN Warehouse.StockItems s
ON ol.StockItemID = s.StockItemID
OPTION (QUERYTRACEON 8649);
END
END
獲取信息
接下來執行存儲過程:exec [Sales].[OrderInfo]
,注意這是一個死循環的存儲過程,幾分鐘之後手動停止。打開查詢存儲查看【資源消耗量最大的幾個查詢】,當然的,這裏第一名的肯定是剛纔的存儲過程。
默認情況下,這裏顯示的是“總持續時間”,我們可以在下圖的【配置】中從【持續時間(ms)】改到【等待時間(ms)】:
把鼠標移到柱狀條上,可以看到等待狀態的信息:
在這個圖上面很明顯看出等待類型和它們的等待時間,是不是比過去的敲命令直觀很多,而且這些還是語句級別的等待信息,在這裏“Parallelism等待時間”是最久的。不過這篇文章不是講解如何分析等待信息,而是介紹如何使用Query Store查看它們。
當然還是有DMV來查詢的,比如下面這個就是查看一個小時內的等待信息,可以調整數字來調控時間範圍:
SELECT TOP (10)
[ws].[wait_category_desc],
[ws].[avg_query_wait_time_ms],
[ws].[total_query_wait_time_ms],
[ws].[plan_id],
[qt].[query_sql_text],
[rsi].[start_time],
[rsi].[end_time]
FROM [sys].[query_store_query_text] [qt]
JOIN [sys].[query_store_query] [q]
ON [qt].[query_text_id] = [q].[query_text_id]
JOIN [sys].[query_store_plan] [qp]
ON [q].[query_id] = [qp].[query_id]
JOIN [sys].[query_store_runtime_stats] [rs]
ON [qp].[plan_id] = [rs].[plan_id]
JOIN [sys].[query_store_runtime_stats_interval] [rsi]
ON [rs].[runtime_stats_interval_id] = [rsi].[runtime_stats_interval_id]
JOIN [sys].[query_store_wait_stats] [ws]
ON [ws].[runtime_stats_interval_id] = [rs].[runtime_stats_interval_id]
AND [ws].[plan_id] = [qp].[plan_id]
WHERE [rsi].[end_time] > DATEADD(MINUTE, -60, GETUTCDATE())
AND [ws].[execution_type] = 0
ORDER BY [ws].[avg_query_wait_time_ms] DESC;
小結
本文又演示了一個Query Store的用法,當然都很簡單,不過作爲一個演示,我覺得已經足夠讓讀者對Query Store引起興趣。
下一文:Azure SQL DB/DW 系列(7)——