はじめに
SQL Serverクエリオプティマイザは、クエリのコンパイル中に統計を利用して、最適なクエリプランを決定します。デフォルトでは、オプティマイザは、テーブルへの変更が多すぎるために統計が古くなっていることに気付いた場合、クエリのコンパイルを続行する直前に統計を更新します(必要な統計のみ、テーブルのすべての統計ではありません) 。
「多すぎる」は、バージョンやトレースフラグ2371が有効になっているかどうかによって異なるため、特定されないことに注意してください。詳細については、このページのAUTO_UPDATE_STATISTICSセクションを参照してください。
同期統計更新の問題
コンパイル前に統計を同期的に更新すると、明らかに遅延が発生し、クエリのコンパイルと実行に時間がかかります。遅延の大きさは、次のようないくつかの要因によって異なります。
- クエリに関係するテーブルの数が「変更が多すぎる」しきい値に達しました
- コンパイルに必要なため、これらの各テーブルの統計を更新する必要がある数
- 関連するテーブルにある行数
- 各統計が作成されたときに指定されたオプション(例:FULLSCANおよびPERSIST_SAMPLE_PERCENT =ON)
そのため、一見ランダムな遅延が発生する可能性があり、特にアプリケーションのクエリタイムアウトが非常に低い場合は、一部のシナリオで問題が発生する可能性があります。
同期統計更新の回避
統計の同期更新を回避するには、次のようなさまざまな方法があります。
- AUTO_UPDATE_STATISTICSをOFFに設定すると、すべての自動更新がオフになり、古い統計から最適ではないクエリプランが発生する可能性を回避するために、独自の統計メンテナンスを実行する必要があります。
- AUTO_UPDATE_STATISTICS_ASYNCをONに設定します。これにより、オプティマイザーが統計を更新する必要があることに気付いた場合、コンパイルを続行し、バックグラウンドタスクが少し後に統計を更新します。これは、AUTO_UPDATE_STATISTICSもONに設定されている場合にのみ機能します。
- 定期的な統計のメンテナンスを実行して、自動の同期または非同期の統計更新がまったく行われないようにします。
SQL Serverコミュニティでは、統計の非同期更新を有効にするかどうかについて多くの議論があります。素敵な妻のキンバリー・L・トリップに彼女の意見を聞いたところ、彼女はいつもそれを有効にすることを勧めています。彼女は私が知る以上に統計について忘れているので、彼女を信じています。 ☺
同期統計の更新の追跡
同期統計の更新を待機していたため、クエリに長い時間がかかったかどうかを判断する明確な方法はありませんでした。 auto_stats を監視している拡張イベントセッションがすでに実行されている場合は、統計の更新が完了した*後*を知ることができます。 非同期でのイベントとフィルタリング 列は0に設定されています。ただし、イベント出力のその列はSQL Server 2017でのみ追加されたものであり、関連するクエリを識別するために何かをキャプチャするアクションも構成する必要があります。
SQL Server 2019には、WAIT_ON_SYNCHRONOUS_STATISTICS_UPDATE待機タイプがあり、一見すると、sys.dm_os_waiting_tasksを調べてクエリが現在何であるかを確認するだけで、クエリが同期統計の更新を待機しているかどうかを簡単に確認できるように見えます。待っています。
残念ながら、そうではありません。
この場合、スレッドは実際には待機していないため、「待機中」という用語はここでは少し誤解を招く可能性があります。この新しい待機タイプは、「プリエンプティブ」待機と呼ばれるものの例です。このモードでは、スレッドは、作業が終了するまでプロセッサ上に留まるモードに切り替わります。ほとんどのプリエンプティブ待機は、スレッドがSQL Serverの外部で呼び出しを行う場合(たとえば、ドメインコントローラーからセキュリティ情報を取得する場合)ですが、スレッドがSQL Server内で何かを実行していて、プロセッサを強制的に譲る前に完了する必要がある場合がありますその4msスレッドクォンタムが期限切れになっているためです。これらのことはどちらもここで起こっていることではありません。この場合、スレッドはプリエンプティブ待機の開始を新しい待機タイプで登録してから、統計の更新を行います。おそらく、途中でPAGEIOLATCH_SHのような他の*実際の*待機が発生します。統計の更新が完了するまで、プリエンプティブ待機は終了せず、待機統計メトリックで考慮されます。
なぜこれが大したことなのですか? DMV sys.dm_os_waiting_tasksは、*本当に*待機しているすべてのスレッドの待機タイプを示します。つまり、スケジューラの待機タスクリストにあるため、同期統計更新スレッドがWAIT_ON_SYNCHRONOUS_STATISTICS_UPDATEを待機していない場合、その待機タイプDMVの出力には表示されません。新しい待機タイプを使用して、クエリが現在統計の更新を待機しているかどうかを確認することはできません。
次の手順を実行することで、これを簡単に証明できます。
- 数十万行のテーブルを作成します
- テーブル列に統計を作成し、オプションとしてFULLSCANおよびPERSIST_SAMPLE_PERCENT =ONを指定して、統計が更新されるたびにテーブル全体が読み取られるようにします。
- 2万行を更新する
- データベースをチェックポイントし、DBCCDROPCLEANBUFFERSを実行します
- 作成した統計を使用して列にWHERE句を指定してSELECTステートメントを実行します
- sys.dm_os_waiting_tasks DMVでSELECTのセッションIDを確認すると、統計の更新によってテーブルが読み取られるため、PAGEIOLATCH_SHを待機している可能性があります。
その失望はさておき、クエリが同期統計の更新を待機しているかどうかを確認できるようにするためのトリックがあります。統計の更新が発生すると、STATMANというコマンドが実行され、 sys.dm_exec_requestsからの出力でそれが発生していることがわかります。 :ステータス (上記で説明したように、スレッドが実行されていても)「一時停止」され、コマンド 「SELECT(STATMAN)」になります。
新しい待機タイプはどのような用途ですか?
新しい待機タイプは、クエリが同期統計の更新を待機していることをすぐに知らせる方法としては使用できませんが、通常の待機統計分析に表示される場合は、ワークロード内の一部のクエリがこれらの遅延に悩まされている可能性があります。 。しかし、それは私に関する限り、その有用性の限界についてです。平均待機時間が平均クエリ実行時間の懸念される割合として表示されない限り、または適切な分析を可能にするために短時間にわたって待機を継続的にキャプチャしている場合を除いて、問題があるかどうかはわかりません。
これは待機タイプであり、前述の要因によって待機時間が大幅に変化する可能性があります。したがって、この待機タイプの存在だけを使用して潜在的な問題を警告します。上記の拡張イベントセッションを実装して、同期統計更新のインスタンスをキャプチャし、その期間が十分に長いかどうかを確認します。是正措置を講じる。
概要
WAIT_ON_SYNCHRONOUS_STATISTICS_UPDATE待機タイプの追加によって、非同期統計更新を構成するか、単にすべての統計保守を自分で行うかが変わるかどうかはわかりませんが、少なくとも今では、クエリが同期統計を待機しているかどうかを確認できます。更新し、さらにアクションを実行します。
次回まで、パフォーマンスのトラブルシューティングをお楽しみください!