Azure SQL DB/DW 系列(4)——Query Store案例(1)——缺失索引

本文屬於Azure SQL DB/DW系列
上一文:Azure SQL DB/DW 系列(3)——Query Store簡介
本文演示如何使用Query Store來找到Missing Index

環境搭建

  本文以AdventureWorks2017作爲演示,使用SQL Server 2019的兼容級別(150)。現在查看一下,這個庫目前是沒有查詢存儲:
在這裏插入圖片描述
  首先需要啓用Query Store,可以在SSMS中實現,不過如果你已經有腳本,那直接用腳本來得更快,另外需要提醒一下,GUI界面的內容根據SSMS版本的不同而不同,比如SSMS 18.4就是一個臨界點,下面兩個圖就是來自於SSMS 17和18.4
在這裏插入圖片描述

USE master
GO
--啓用Query Store
ALTER DATABASE AdventureWorks2017 SET QUERY_STORE = ON
GO
--配置Query Store
ALTER DATABASE AdventureWorks2017 SET QUERY_STORE (OPERATION_MODE = READ_WRITE, CLEANUP_POLICY = (STALE_QUERY_THRESHOLD_DAYS = 30),     DATA_FLUSH_INTERVAL_SECONDS = 300, INTERVAL_LENGTH_MINUTES = 10)
GO

  配置說明:

  • OPERATION_MODE:可以爲 READ_WRITE(默認)或 READ_ONLY
  • CLEANUP_POLICY :配置 STALE_QUERY_THRESHOLD_DAYS 參數,以指定數據在查詢存儲中保留的天數 。 默認值爲 30。
  • DATA_FLUSH_INTERVAL_SECONDS :Query Store的數據被刷進磁盤永久保存的頻率,這裏的單位是秒,用GUI的話顯示的是分鐘,建議大概15或者5分鐘(300秒),太頻繁會導致服務器壓力上升。
  • INTERVAL_LENGTH_MINUTES :以分鐘爲單位。確定運行時執行統計數據聚合到查詢存儲中的時間間隔 。 爲了優化空間使用情況,將在固定時間窗口上聚合運行時統計信息存儲中的運行時執行統計信息。 此固定時間窗口通過 INTERVAL_LENGTH_MINUTES 進行配置。 默認值是 60秒,也就是1分鐘。
    在這裏插入圖片描述
      執行完之後,【查詢存儲】就出來了。不過提醒一下,如果系統在運行,甚至負載很重的時候,啓用query store可能會挺久,比如10分鐘。
      然後創建一個非常簡單的Missing Index的場景,第一個會 出現Missing Index,第二個不會,這個可以在執行計劃中看到,需要多運行幾次以便查詢存儲能夠捕獲足夠的信息:
/* 多次運行以便產生足夠的活動 */
select * 
from [Person].[Person]
where MiddleName='A'
GO



select FirstName,MiddleName,LastName
from [Person].[Person]
where FirstName like 'A%'
GO

在這裏插入圖片描述

GUI查看結果

  首先使用GUI來查看,查詢存儲側重於使用最多資源的查詢、總體資源消耗以及使用不同的計劃變慢的查詢。查詢存儲便於查看這些類型的查詢的計劃,並且你可以直觀地識別執行計劃中是否有該時間段的索引請求。
  我們打開如圖所示的[資源消耗量最多的幾個查詢]:
在這裏插入圖片描述
  這裏會顯示當前庫在過去一小時內25個資源消耗者(resource consumers)的信息,默認會對第一個也就是top 1顯示一些更詳細的信息,並且柱狀圖是綠色的。
  從圖上可以看到,missing index在上面,因爲下方的執行計劃有一行缺少索引的綠色字。從柱狀圖的高矮可以看出它的邏輯讀比第二個高得多。如果你把鼠標移到右上角的那個區域的點上,還可以看到它在這個時間段中運行過了9 次。光這幾個信息,Query Store已經比其他工具優秀很多。
在這裏插入圖片描述
  接下來查看一下不存在Missing Index的請求會是怎樣的。現在我們點開第二個柱子,注意這是特例,並不是每個實際環境中都會按照這個方式來顯示:
在這裏插入圖片描述

雖然執行次數不一樣,不過簡單計算一下也可以看到其IO遠比上面的低。當然,其實這兩個查詢可比性不高,這裏只是爲了演示如何找到缺少索引而已。注重方法而不是實際內容。

DMV查看結果

  如果嫌GUI操作慢,可以直接使用下面的DMV語句來查看。我這裏顯示的是24小時內的內容,讀者可以按照自己的需要調整時間間隔,但是需要提醒一下,下面的SQL 只是顯示最近收集的執行計劃,在一個長時間內,某個查詢的執行計劃可能會因爲很多因素而變化,並且不是所有的執行計劃都一定會存在缺失索引,所以其實DMV可能並不可以完全替代GUI,需要搭配來用:

SELECT
    SUM(qrs.count_executions) * AVG(qrs.avg_logical_io_reads) as est_logical_reads,
    SUM(qrs.count_executions) AS sum_executions,
    AVG(qrs.avg_logical_io_reads) AS avg_avg_logical_io_reads,
    SUM(qsq.count_compiles) AS sum_compiles,
    (SELECT TOP 1 qsqt.query_sql_text FROM sys.query_store_query_text qsqt
        WHERE qsqt.query_text_id = MAX(qsq.query_text_id)) AS query_text,	
    TRY_CONVERT(XML, (SELECT TOP 1 qsp2.query_plan from sys.query_store_plan qsp2
        WHERE qsp2.query_id=qsq.query_id
        ORDER BY qsp2.plan_id DESC)) AS query_plan,
    qsq.query_id,
    qsq.query_hash
FROM sys.query_store_query qsq
JOIN sys.query_store_plan qsp on qsq.query_id=qsp.query_id
CROSS APPLY (SELECT TRY_CONVERT(XML, qsp.query_plan) AS query_plan_xml) AS qpx
JOIN sys.query_store_runtime_stats qrs on qsp.plan_id = qrs.plan_id
JOIN sys.query_store_runtime_stats_interval qsrsi on qrs.runtime_stats_interval_id=qsrsi.runtime_stats_interval_id
WHERE	
    qsp.query_plan like N'%<MissingIndexes>%'
    and qsrsi.start_time >= DATEADD(HH, -24, SYSDATETIME())
GROUP BY qsq.query_id, qsq.query_hash
ORDER BY est_logical_reads DESC
GO

在這裏插入圖片描述

小結

  本例子演示瞭如何使用Query Store查詢Missing Index,其實讀者可以看出,我實際上是查詢資源消耗,因爲缺失索引幾乎都會造成資源的過度消耗。
  選用這個作爲例子是因爲首先Missing Index影響非常大,其次它比較好捕獲,另外從執行計劃裏面也很容易看出來。當然還有很多更深入的Query Store案例,接下來會再演示幾個。
  關於Missing Index,還可以看一下我過去的文章:SQL Server 索引維護(1)——如何獲取索引使用情況

下一文:Azure SQL DB/DW 系列(5)——Query Store案例(2)——計劃迴歸

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章