クエリストアとプランキャッシュの情報の格納単位が気になったので軽くまとめてみたいと思います。
今回は以下のクエリを実行してみます。
SELECT * FROM sys.objects WAITFOR DELAY '00:00:05' SELECT * FROM sys.tables OPTION(RECOMPILE)
このクエリですが、一つのバッチと 3 つのステートメントで構成されているクエリとなります。
このクエリを実行した後に、以下のクエリでクエリストアとプランキャッシュの情報を確認してみます。
FROM sys.query_store_query_text qsqt LEFT JOIN sys.query_store_query qsq ON qsqt.query_text_id = qsq.query_text_id LEFT JOIN sys.query_store_plan qsp ON qsp.query_id = qsq.query_id WHERE query_sql_text LIKE '%sys.objects%' or query_sql_text LIKE '%sys.tables%' SELECT SUBSTRING(text, ([statement_start_offset] / 2) + 1, ((CASE [statement_end_offset] WHEN -1 THEN DATALENGTH(text) ELSE [statement_end_offset] END - [statement_start_offset]) / 2) + 1) AS [stmt_text], text, query_plan FROM sys.dm_exec_query_stats CROSS APPLY sys.dm_exec_sql_text(sql_handle) CROSS APPLY sys.dm_exec_query_plan(plan_handle) WHERE text LIKE '%sys.objects%' OR text LIKE '%sys.tables%' OPTION (RECOMPILE)
実行の結果はこちらに。
クエリストアについてはステートメントで情報が格納されています。
プランキャッシュについてもステートメント単位で情報が格納されているのですが、バッチの中でどのステートメントが該当しているかはオフセット情報で管理がされています。
そのため、「sys.objects」を例にした場合の、クエリのプランの情報が以下のように異なっています。
# 上:クエリストア/下:プランキャッシュ
クエリストアの場合、ステートメント単位で情報を管理しており、クエリのコンパイル時間について、列として簡単に取得することができます。
プランキャッシュについてもステートメントレベルのコンパイル時間は保持しているのですが、単純な列としてではなく、実行プランを開き、該当のステートメントの、「CompileTime」から確認をする必要がありましたので少し手間がかかっていたかと思います。
クエリストアでは、格納されている情報がステートメント/実行プラン単位となりますので、実行プランが変わった際のコンパイル時間の変化についてもプランキャッシュから情報を取得するより、簡単に取得できるのは強みになりそうですね。
どのようなケースでクエリストアが効果を発揮するかを考えると奥が深いです。