プライマリで一時的に時間がかかる読み取り専用レプリカでの長時間実行クエリ


8

私は次のように4ノードAGセットアップを持っています。

すべてのノードのVMハードウェア構成:

  • Microsoft SQL Server 2017 Enterprise Edition(RTM-CU14)(KB4484710)
  • 16個のvCPU
  • 356 GB RAM(これまでの話...)
  • 最大並列度:1(アプリベンダーの要求に応じて)
  • 並列処理のコストしきい値:50
  • 最大サーバーメモリ(MB):338944(331 GB)

AG構成:

  • ノード1:プライマリまたは同期コミット読み取り不可セカンダリ、自動フェイルオーバー用に構成
  • ノード2:プライマリまたは同期コミット、読み取り不可のセカンダリ、自動フェイルオーバー用に構成
  • ノード3:読み取り可能なセカンダリセット、非同期コミット、手動フェイルオーバー用に構成
  • ノード4:非同期のコミットを備えた読み取り可能なセカンダリセット、手動フェイルオーバー用に構成

問題のクエリ:

このクエリについては、まったくおかしなことは何もありません。アプリケーション内のさまざまなキューにある未解決の作業項目の概要を提供します。以下の実行プランのリンクの1つからコードを確認できます。

プライマリノードでの実行動作:

プライマリノードで実行した場合、実行時間は通常約1秒です。以下は実行計画です。以下は、プライマリノードからのSTATISTICS IOおよびSTATISTICS TIMEからキャプチャされた統計です。

(347 rows affected)
Table 'Worktable'. Scan count 647, logical reads 2491, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'workitemlc'. Scan count 300, logical reads 7125, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Workfile'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'schedulertask'. Scan count 1, logical reads 29, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'wfschedulertask'. Scan count 1, logical reads 9, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'schedulerservice'. Scan count 1, logical reads 12, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'schedulerworkerpool'. Scan count 1, logical reads 3, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'itemlc'. Scan count 1, logical reads 26372, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

(1 row affected)

 SQL Server Execution Times:
   CPU time = 500 ms,  elapsed time = 656 ms.
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.

読み取り専用セカンダリノードでの実行動作:

読み取り専用のセカンダリノード(ノード3またはノード4)で実行する場合、このクエリは同じ実行プラン(これは別のプランリンクです)を使用し、ほぼ同じ実行統計が表示されます(たとえば、さらにいくつかのページがある場合があります)スキャンはこれらの結果が常に変化するため)、CPU時間を除いて、非常によく似ています。以下は、読み取り専用のセカンダリノードからSTATISTICS IOおよびSTATISTICS TIMEからキャプチャされた統計です。

(347 rows affected)
Table 'Worktable'. Scan count 647, logical reads 2491, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'workitemlc'. Scan count 300, logical reads 7125, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Workfile'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'schedulertask'. Scan count 1, logical reads 29, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'wfschedulertask'. Scan count 1, logical reads 9, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'schedulerservice'. Scan count 1, logical reads 12, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'schedulerworkerpool'. Scan count 1, logical reads 3, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'itemlc'. Scan count 1, logical reads 26372, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

(1 row affected)

 SQL Server Execution Times:
   CPU time = 55719 ms,  elapsed time = 56335 ms.
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.

その他の情報:

また、このクエリの実行中にセカンダリsp_WhoIsActiveと両方でPaul RandalのWaitingTasks.sqlスクリプトを実行しましたが、待機がまったく発生していないため、率直にイライラします。

ここに画像の説明を入力してください

同期ステータスは実際には非常に良好であるため、これはAGレイテンシの場合にも見えません。

--https://sqlperformance.com/2015/08/monitoring/availability-group-replica-sync

SELECT 
       ar.replica_server_name, 
       adc.database_name, 
       ag.name AS ag_name, 
       drs.is_local, 
       drs.synchronization_state_desc, 
       drs.synchronization_health_desc, 
       --drs.last_hardened_lsn, 
       --drs.last_hardened_time, 
       drs.last_redone_time, 
       drs.redo_queue_size, 
       drs.redo_rate, 
       (drs.redo_queue_size / drs.redo_rate) / 60.0 AS est_redo_completion_time_min,
       drs.last_commit_lsn, 
       drs.last_commit_time
FROM sys.dm_hadr_database_replica_states AS drs
INNER JOIN sys.availability_databases_cluster AS adc 
       ON drs.group_id = adc.group_id AND 
       drs.group_database_id = adc.group_database_id
INNER JOIN sys.availability_groups AS ag
       ON ag.group_id = drs.group_id
INNER JOIN sys.availability_replicas AS ar 
       ON drs.group_id = ar.group_id AND 
       drs.replica_id = ar.replica_id
ORDER BY 
       ag.name, 
       ar.replica_server_name, 
       adc.database_name;

ここに画像の説明を入力してください

このクエリは最悪の犯罪者のようです。プライマリノードで1秒未満かかる他のクエリは、セカンダリノードで1〜5秒かかる場合があります。動作はそれほど深刻ではありませんが、問題を引き起こしているようです。

最後に、サーバーも調べて、A / Vスキャンなどの外部プロセス、予期しないI / Oを生成する外部ジョブなどがないかを確認しました。これは、SQL Serverプロセス以外の原因が原因ではないと思います。

質問:

私がいるのは正午だけで、すでに長い日だったので、ここで明らかな何かを見逃しているのではないかと思います。それか、設定に誤りがあります。これは、この環境に関連するベンダーとMSへの呼び出しが何度もあったために発生する可能性があります。

私の調査のすべてについて、私はこのパフォーマンスの違いを引き起こしているものを見つけることができないようです。セカンダリノードで何らかの待機が発生することを期待しますが、何も発生しません。これをトラブルシューティングして根本的な原因を特定するにはどうすればよいですか?誰かが以前にこの動作を見て、それを解決する方法を見つけましたか?

更新#1 3番目のノード(読み取り専用レプリカの1つ)の状態を読み取り不可に交換してから、テストとして読み取り可能に戻した後、そのレプリカは開いているトランザクションによって引き続き保留されており、クライアントクエリはHADR_DATABASE_WAIT_FOR_TRANSITION_TO_VERSIONING待つ。

DBCC OPENTRANコマンドを実行すると、次の結果が得られます。

Oldest active transaction:
    SPID (server process ID): 420s
    UID (user ID) : -1
    Name          : QDS nested transaction
    LSN           : (941189:33148:8)
    Start time    : May  7 2019 12:54:06:753PM
    SID           : 0x0
DBCC execution completed. If DBCC printed error messages, contact your system administrator.

このSPIDをで検索すると、コマンドとしてリストされてsp_who2いるBACKGROUNDプロセスQUERY STORE BACKとして表示されます。

TLogバックアップをとることできますが、この解決されたバグと同様の機能が実行されていると思われるため、本日、この特定の問題についてMSでチケットを開く予定です。

そのチケットの結果に応じて、Joeの提案に従ってコールスタックトレースをキャプチャして、どこに行くかを確認します。

最終更新(問題の自己解決)

(上記のように)開いているクエリストアトランザクションの52時間のマークを超えた後、AGは自動的にフェールオーバーすることを決定しました。これが発生する前に、追加のメトリックをいくつか取得しました。Seanによって提供されたこのリンクによれば、問題のデータベースには、このデータベース専用の非常に大きなバージョンストアがありました。特に、ある時点で、reserved_page_countフィールドに1651360ページ、reserved_space_kb値に13210880を記録しました。

エラーログごとに、フェールオーバーがに関連するトランザクション硬化障害の5分の大洪水後に発生したQDS base transactionQDS nested transactionの取引。

私の場合、フェイルオーバーによって約10分の停止が発生しました。データベースのサイズは〜6TBで、非常にアクティブであるため、実際にはかなり良いと思いました。この間、新しいプライマリノードはオンラインでしたが、すべてが待機QDS_LOADDBタイプで待機していたため、クライアントクエリを完了できませんでした。

フェイルオーバー後、バージョンストア番号はの176 reserved_page_countと1408に減少しましたreserved_space_kb。セカンダリ読み取り専用レプリカに対するクエリも、プライマリから実行された場合と同じように迅速に実行され始めたため、フェイルオーバーの結果、動作が完全に消えたように見えます。


プライマリで開いているトランザクションの長さを変更できないか、セカンダリで負荷の高いクエリを制御できない場合は、ワークロードをプライマリにポイントすると、長時間実行されている問題が軽減されますが、他の一般的なクエリ関連の問題が発生する可能性があります。物事を片付けるためにレプリカを読み取り不可に設定するのは通常のことではありませんが、これは優れたトラブルシューティング手法です。根本的な原因を修正できるかどうか、または状況が悪化したときの症状だけに依存します。
Sean Gallardy-退職したユーザー

1
ジョン、こんにちは。この質問をフォローしてください。ただ言及したかったのQDS_LOADDBですが、将来的にそれを回避したいがクエリストアをオンにしたい場合は、マイクロソフトが推奨するこれらのトレースフラグを使用できます。特に7752では、クエリストアが初期化される前にクエリを実行できます(そのため、一部のクエリを見逃す可能性がありますが、データベースは稼働しています)。
Josh Darnell、

John-ワークロードがパラメーター化されていない、パラメーター化が不十分、または非常にアドホックである可能性はありますか?アドホックタイプのワークロードに関連するQDSの問題をいくつか見ました
AMtwo

@AMtwoはい、データベースにヒットするクエリの大部分はクライアントで生成され、パラメーター化されません(つまり、アドホッククエリ)。
John Eisbrener、

@JoshDarnellトレースフラグ7752は特に便利です。先端をありがとう!
John Eisbrener、

回答:


9

これはバージョンストアであることが100%確実ではないので、ジョーの回答に加えてこの回答ですが、これまでのところ、問題の一部であることを示唆する十分な証拠があります。

セカンダリレプリカが読み取り可能としてマークされている場合、バージョン情報の安定した状態を最初に取得して、セカンダリでのすべての読み取り操作の既知の適切な開始点を取得する必要があります。これが移行を待機していて、プライマリにまだオープントランザクションがある場合、これはHADR_DATABASE_WAIT_FOR_TRANSITION_TO_VERSIONING、プライマリがかなりのデータチャーンを経験している(または少なくとも誰かが本当に長いトランザクションを開いているまた、良くありません)。トランザクションが開いている時間が長く、データの変更が多いほど、より多くのバージョン管理が行われます。

セカンダリレプリカは、セッションのカバーの下でスナップショットアイソレーションを使用して読み取り可能なステータスを実現します。ただし、セッション情報を確認すると、コミットされたデフォルトの読み取りで表示されます。スナップショットの分離は楽観的であり、バージョンストアを使用するため、すべての変更をバージョン管理する必要があります。これは、プライマリでデータのチャーンが高いときに、セカンダリで実行中のクエリ(および実行時間が長くなる可能性がある)が多い場合に悪化します。一般に、これはOLTPシステムのいくつかのテーブルでのみ現れますが、アプリケーションとワークロードに完全に依存しています。

バージョンストア自体は世代ごとに測定され、バージョンストアの使用を必要とするクエリが実行されると、バージョン管理レコードポインターがその行のTempDBチェーンを指すために使用されます。チェーンと言います。これは、その行のバージョンのリストであり、結果全体がその時点でのデータと一致するように、トランザクション全体の開始タイムスタンプに基づいて適切なバージョンを見つけるためにチェーン全体を順番に調べる必要があるためです。

プライマリレプリカとセカンダリレプリカで長時間実行されているトランザクションが原因で、バージョンストアにこれらの行の世代が多数ある場合、他のすべてのアイテムがまったく同じように見える一方で、クエリの実行に平均より長い時間がかかり、通常はより高いCPUの形になります。 -実行計画、統計、返される行など。チェーンのウォーキングはほぼ純粋にCPU操作であるため、チェーンが非常に長くなり、返される行の量が非常に多くなると、(線形ではありませんが、クエリの時間を増やすことができます)。

できることは、プライマリとセカンダリの両方でトランザクションの長さを制限して、TempDBでバージョンストアが大きくなりすぎないようにしながら、世代数が多くならないようにすることです。バージョンストアのクリーンアップは約1分に1回行われますが、クリーンアップでは、同じ世代のすべてのバージョンを削除してから削除する必要があり、最も古いバージョンが不要になるまで将来のすべてのバージョンをクリーンアップできません。したがって、クエリが長時間実行されると、多くの未使用の世代を効果的にクリーンアップできなくなる可能性があります。

レプリカを読み取り可能モードに切り替えたり、読み取り可能モードから切り替えたりすると、バージョンストアが読み取り不可能になるため、バージョンストアも消去されます。

他にもプレイできるアイテムは他にもありますが、現在のデータとレプリカの反応を考えると、これが最ももっともらしいようです。

TempDBバージョン管理DMV(ADRバージョン管理と混同しないでください)。


に対してクエリを実行するsys.dm_tran_version_store_space_usageと、reserved_pa​​ge_countとして1651360が返され、問題のデータベースのreserved_space_kb値として13210880が返されます。ただし、この問題は特定されているため、表示は適切に見えます。詳しい説明ありがとうございます!
John Eisbrener、

1
私はあなたが問題を正しく呼び出したことを約103%確信しています。質問をいくつかの更新で更新しましたが、洞察をありがとう!
John Eisbrener、

8

免責事項:可用性グループについては何も知りませんが、必要以上にCPUを使用しているように見えるクエリのトラブルシューティングについては少し知っています。

CPUの使用量が多すぎるという問題があります。待機について言うべき重要なことの1つは、待機のほとんどすべてがCPUビジーではないことです。ワーカーが待機状態になると、ワーカーは解放され、SQLOSのスケジューラで実行されなくなります。したがって、次の実行統計を含むMAXDOP 1クエリがあるとします。

CPU時間= 55719 ms、経過時間= 56335 ms。

クエリのCPU使用率がほぼ99%に達します。そのクエリに意味のある待機統計が必要なのはなぜですか?外部またはプリエンプティブな待機などのCPUビジー待機がある場合、いくつかが表示されることがありますが、それも保証されていません。要するに、ここでは待機統計はそれほど役に立たない可能性があるということです。

大まかな順序で確認することがいくつかあります(順序は環境についての知識に依存します)。

  • セカンダリサーバーには、拡張イベント、トレース、プロファイリングなどの高価な監視が行われていますか?
  • セカンダリサーバーのハードウェアはプライマリとほぼ同じですか?
  • セカンダリサーバーに構成またはソフトウェアの問題はありますか?
  • 重要な待機またはラッチはありますか?クエリに適用できない場合がありますが、それでも手掛かりが得られる場合があります。
  • 重要なスピンロックはありますか?
  • 手がかりを与える可能性のある他のDMVまたはSQL Server内で確認できるものはありますか?可用性グループが問題の重要な部分である可能性が高いとおっしゃいました。
  • ETWトレースは何を教えてくれますか?
  • どのようなサポート契約がありますか?

上記のほとんどは、さまざまなブログ投稿やドキュメントで十分にカバーされていますが、ETWトレースについて詳しく説明します。SQL Serverが特定のクエリに大量のCPUを使用している理由を知りたい場合、およびホストにアクセスできる場合は、常にETWトレースを実行して、コールスタックを表示し、さまざまなコールスタックが実行しているCPUの量を確認できます。つまり、ホストOSは、質問する方法を知っている場合、どのCPUが使用されているかを喜んで教えてくれます。ETWトレースを行う一般的な方法には、Windows Performance RecorderPerfViewがあります。

これらの結果を理解するには、内部に関する深い知識が必要であり、間違った結論にたどり着きやすいです。多くの場合、生データを収集し、専門家にそれを確認するよう依頼するのが最善です。トレースを実行するときは、SQL Serverで実行するアクティビティをできるだけ少なくします。以下に、ETWトレースを使用してSQL Serverに関する結論を導き出す、いくつかの回答を示します。

あなたの場合、45秒のクエリの実行中にコールスタックを収集できれば、問題の性質について非常に役立つ手掛かりが得られると思います。


5

問題が自己解決したので、私はその原因を推測する必要があります(意図的なリズムではありません)。Seanの投稿と、開いているクエリストアトランザクションが私のバージョンストアサイズの増加の根本的な原因であると思われるという事実(たとえば、HADR_DATABASE_WAIT_FOR_TRANSITION_TO_VERSIONING待機)に、クエリストアが提示した。このデータベースは大きく(〜6TB)、かなりアクティブであり、データベースにヒットするクエリの大部分はクライアントで生成され、パラメーター化されていません(つまり、アドホッククエリ)。このシナリオでは多くの用途があります。そのため、今後のメンテナンスウィンドウでこの環境のクエリストアを無効にします。その後、この動作は再び発生しないと思います。

マイクロソフトでチケットをオープンしましたが、PSSDIAGトレースなどを介して詳細な分析を行う前に問題が解決されたため、タイミングは好ましくありませんでした。これが私たちが遭遇したバグである場合、ローカライズされたテストをいくつか実行し、この問題を再現できることを期待しています。さらに恒久的な解決策に関する更新が確認された場合は、この回答も必ず更新します。

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