クエリストア検索を終了しない


10

最初から私の質問/問題はこの前のものと似ていると言いますが、原因または開始情報が同じであるかどうかわからないため、質問をいくつか詳細に投稿することにしました。

手元の問題:

  • 奇妙な時間(営業日の終わり近く)に、本番インスタンスの動作が不安定になります。
    • インスタンスのCPU使用率が高い(ベースラインが約30%の場合、約2倍になり、まだ増加し続けていた)
    • 1秒あたりのトランザクション数の増加(ただし、アプリの負荷には変化が見られません)
    • アイドルセッションの数の増加
    • この動作を表示しなかったセッション間の奇妙なブロッキングイベント(コミットされていない読み取りセッションでもブロッキングが発生していました)
    • 間隔の上位の待機は1位で非ページラッチで、ロックは2位でした。

初期調査:

  • sp_whoIsActiveを使用して、監視ツールによって実行されたクエリが非常に低速で実行され、大量のCPUを取得することを決定したことがわかりました。
  • その分離レベルはコミットされずに読み取られました。
  • 奇妙な数字が見られた計画を調べました。StatementEstRows= "3.86846e + 010"で、約150 TBの推定データが返されます。
  • 監視ツールのクエリモニター機能が原因であると考えたため、この機能を無効にしました(プロバイダーにチケットを開いて、問題が発生しているかどうかを確認しました)
  • その最初のイベントから、それはさらに数回起こりました。セッションを終了するたびに、すべてが通常に戻ります。
  • クエリがクエリストアの監視のためにBOLでMSによって使用されるクエリの1つに非常に類似していることがわかります-パフォーマンスが最近低下したクエリ(異なる時点での比較)
  • 同じクエリを手動で実行し、同じ動作を確認します(使用されるCPUが増え続ける、ラッチ待機が増える、予期しないロックなど)。

有罪の質問:

Select qt.query_sql_text, 
    q.query_id, 
    qt.query_text_id, 
    rs1.runtime_stats_id AS runtime_stats_id_1,
    interval_1 = DateAdd(minute, -(DateDiff(minute, getdate(), getutcdate())), rsi1.start_time), 
    p1.plan_id AS plan_1, 
    rs1.avg_duration AS avg_duration_1, 
    rs2.avg_duration AS avg_duration_2,
    p2.plan_id AS plan_2, 
    interval_2 = DateAdd(minute, -(DateDiff(minute, getdate(), getutcdate())), rsi2.start_time), 
    rs2.runtime_stats_id AS runtime_stats_id_2
From sys.query_store_query_text AS qt 
Inner Join sys.query_store_query AS q 
    ON qt.query_text_id = q.query_text_id 
Inner Join sys.query_store_plan AS p1 
    ON q.query_id = p1.query_id 
Inner Join sys.query_store_runtime_stats AS rs1 
    ON p1.plan_id = rs1.plan_id 
Inner Join sys.query_store_runtime_stats_interval AS rsi1 
    ON rsi1.runtime_stats_interval_id = rs1.runtime_stats_interval_id 
 Inner Join sys.query_store_plan AS p2 
    ON q.query_id = p2.query_id 
Inner Join sys.query_store_runtime_stats AS rs2 
    ON p2.plan_id = rs2.plan_id 
Inner Join sys.query_store_runtime_stats_interval AS rsi2 
    ON rsi2.runtime_stats_interval_id = rs2.runtime_stats_interval_id
Where rsi1.start_time > DATEADD(hour, -48, GETUTCDATE()) 
    AND rsi2.start_time > rsi1.start_time 
    AND p1.plan_id <> p2.plan_id
    AND rs2.avg_duration > rs1.avg_duration * 2
Order By q.query_id, rsi1.start_time, rsi2.start_time

設定と情報:

  • Windows Server 2012R2クラスター上のSQL Server 2016 SP1 CU4 Enterprise
  • クエリストアを有効にし、デフォルトとして構成(設定は変更されません)
  • SQL 2005インスタンスからインポートされたデータベース(互換性レベル100のまま)

経験的観察:

  • 非常に奇妙な統計のため、不適切な推定計画で使用されているすべての* plan_persist **オブジェクトを取得し(実際の計画はまだない、クエリが完了しない)、統計を確認しました。計画で使用されているインデックスの一部には統計がありませんでした(DBCC SHOWSTATISTICSは何も返しませんでした。sys.statsから選択すると、一部のインデックスに対してNULL stats_date()関数が表示されました

迅速で汚れたソリューション:

  • クエリストアに関連するシステムオブジェクトの不足している統計を手動で作成する、または
  • 新しいCE(トレースフラグ)を使用してクエリを強制的に実行します。これにより、必要な統計情報も作成/更新されます。
  • データベースの互換性レベルを130に変更します(デフォルトで新しいCEを使用します)

だから、私の本当の質問は:

クエリストアのクエリがインスタンス全体でパフォーマンスの問題を引き起こすのはなぜですか?クエリストアのバグ領域にいますか?

PS:いくつかのファイル(印刷画面、IO統計、計画)を少しでアップロードします。

Dropboxに追加されたファイル。

計画1-生産における最初の奇抜な推定計画

計画2-テスト環境での実際の計画、古いCE(同じ動作、同じ奇抜な統計)

計画3-テスト環境での実際の計画、新しいCE


1
最終的にクエリストアを無効にしました。根本的な原因を確認しました(確かに複数の問題がありました)。私の場合、CPUは、クエリストアの統計情報を表示するためにクリックしたすべてのものを増やします。
A_V 2018年

回答:


6

回答で述べたように、経験的テストでは、sys.plan_persisted *システムオブジェクトにインデックスがあり、統計は(何も)作成されていません。これは、データベースがSQL 2005インスタンスから移行され、しばらく互換性レベル100に保たれているため、新しいCEを使用できなかったためと考えられます。

行数チェック:

Select count(1) from NoNameDB.sys.plan_persist_runtime_stats with (nolock) --60362   
Select count(1) from NoNameDB.sys.plan_persist_plan with (nolock) --1853    
Select count(1) from NoNameDB.sys.plan_persist_runtime_stats_interval with (nolock) --671    
Select count(1) from NoNameDB.sys.plan_persist_query with (nolock) --1091    
Select count(1) from NoNameDB.sys.plan_persist_query_text with (nolock) --911

これは、最初の見積もりが間違っていたことを示しています。DAC接続で実行されます。それ以外の場合、テーブルはクエリに使用できません。

統計チェック:

DBCC SHOW_STATISTICS ('sys.plan_persist_runtime_stats_interval', plan_persist_runtime_stats_interval_cidx);    
DBCC SHOW_STATISTICS ('sys.plan_persist_runtime_stats', plan_persist_runtime_stats_idx1);    
DBCC SHOW_STATISTICS ('sys.plan_persist_runtime_stats', plan_persist_runtime_stats_cidx);    
DBCC SHOW_STATISTICS ('sys.plan_persist_plan', plan_persist_plan_cidx);    
DBCC SHOW_STATISTICS ('sys.plan_persist_plan', plan_persist_plan_idx1);    
DBCC SHOW_STATISTICS ('sys.plan_persist_query', plan_persist_query_cidx)    
DBCC SHOW_STATISTICS ('sys.plan_persist_query_text', plan_persist_query_text_cidx);

これは、一部のインデックスに空の統計(欠落、なし、ゼロ)があったことを示しています。

初期修正:

UPDATE STATISTICS sys.plan_persist_runtime_stats WITH fullscan;
UPDATE STATISTICS sys.plan_persist_plan WITH fullscan;
UPDATE STATISTICS sys.plan_persist_runtime_stats_interval WITH fullscan;
UPDATE STATISTICS sys.plan_persist_query WITH fullscan;
UPDATE STATISTICS sys.plan_persist_query_text WITH fullscan;

この種類の統計を修正し、クエリを10〜12秒で完了させました。

2番目の修正

(テスト環境でのみ検証されます)クエリに最適な統計を示したので、おそらく適切なものは、データベースの互換性レベルを130に変更することでした。最終結果は、クエリが約10〜12秒で終了したことです。通常の数値統計(1万行)。

中間修正

DBCC TRACEON (2312) -- new CE

システムの隠しテーブルの統計に関するいくつかの関連ヘルプ


3

SSMSで実際のプランを開いてCPU使用率を調べる(またはXMLを調べる)と、目に見える根本的な問題は、TVFノード32です。遅いクエリストアクエリの原因は、メモリ内TVFへの繰り返しアクセスです

TVFコスト

これらのTVFから返される行の数は関係ありません。それらがアクセスされる回数だけです。修正は、プランを何度も読まないようにするためにできることです。

限られたデバッグ(スキルと時間の両方)に基づいて、私の仮説は、クエリストアデータの特定のインメモリコンポーネントに割り当てられたメモリ全体が、TVFの実行ごとにスキャンされるというものです。sp_query_store_flush_dbまたはでこのメモリ割り当てに影響を与えることはできませんDBCC FREESYSTEMCACHE

これまでの成功した回避策には、プランガイド、ヒント(OPTION(HASH JOIN, LOOP JOIN)これまでのところ十分に機能している)、AGの読み取り専用ノードでのクエリストアクエリの実行が含まれます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.