SQL Server の統計情報の自動更新はデフォルトの設定では同期的更新が行われます。
統計情報の自動更新のしきい値を超える更新が行われた場合、該当の統計情報を利用するクエリが実行された場合、そのクエリが統計情報の更新のトリガーとなり、統計情報の同期的自動更新が行われます。
この際、クエリのタイムアウトが絡むと、統計情報の自動更新の挙動で気を付ける点があります。
Contents
統計情報の同期的自動更新とクエリタイムアウト
統計情報の自動更新が行われると、自動更新をトリガーしたクエリの実行状況は次のようになります。
統計情報の自動更新のトリガーとなったクエリを実行したセッションの「command」は、「SELECT (STATMAN)」というような状態となり、統計情報の更新が行われている状態となります。
この際、該当の統計情報の更新により待機されている場合には「WAIT_ON_SYNC_STATISTICS_REFRESH」という待機事象が発生する可能性もあります。
これらの情報は、SQL Server 2019 からモニターできる ようになったものとなり、このような情報が確認できた場合は、統計情報の同期的な自動更新により同時実行性の低下につながった可能性を考える必要が出てきます。
統計情報の同期的な更新による処理時間は「ユーザーがー実行したクエリの実行時間に含まれる」ことになります。
そのため、統計情報の同期的自動更新に起因してクエリタイムアウトが発生する可能性があります。(サンプリングしてデータにアクセスしますので通常の状態であれば、タイムアウトの要因になる程の処理時間にはならないはずではありますが)
このクエリタイムアウトには二つのケースがあるかと。
- 統計情報の同期的自動更新を実行中にクエリタイムアウトが発生
- 統計情報の同期的自動更新は完了したが、自動更新をトリガーしたクエリでクエリタイムアウトが発生
この二つのケースでは、統計情報の更新の処理の完了状況が異なります。
統計情報の同期的自動更新を実行中にクエリタイムアウトが発生
「1.」でクエリタイムアウトが発生した場合、統計情報の更新が完了していない状態となります。
統計情報の更新を実施するためには、統計情報に関連する列の情報を取得する必要があり、通常は次のような設定でクエリが実行されます。
(@samplePercent float) SELECT StatMan([SC0], [SB0000]) FROM (SELECT TOP 100 PERCENT [SC0], step_direction([SC0]) over (order by NULL) AS [SB0000] FROM (SELECT [no] AS [SC0] FROM [dbo].[accesslog_tmp] TABLESAMPLE SYSTEM (@samplePercent PERCENT) WITH (READUNCOMMITTED) ) AS _MS_UPDSTATS_TBL_HELPER ORDER BY [SC0], [SB0000] ) AS _MS_UPDSTATS_TBL OPTION (MAXDOP 16, RECOMPILE)
- READUNCOMMITTED を指定
- TABLESAMPLE SYSTEM (@samplePercent PERCENT) により、サンプリングを指定
- MAXDOP は 16 を上限
統計情報のベースとなるデータを取得する際の同時実行性の低下は抑えられるように考慮したオプションが使用されており、通常はそれほど時間がかからずにデータにアクセスできるようなクエリにはなっています。
しかし、何らかの同時実行性の低下により、統計情報を更新するためのデータの取得に時間がかかり、上述のクエリの実行中にクエリタイムアウトが発生するケースがあります。
このような「統計情報を更新するために実行されたクエリ」でクエリタイムアウトが発生すると、統計情報の自動更新による統計の更新が行われていない状態となります。
このようなクエリタイムアウトが発生した場合、次回、該当の統計情報を使用するクエリが実行された場合に、再度、同期的な自動更新が行われることになります。
通常は発生する可能性が低い極端な例となりますが、統計情報の自動更新中に毎回クエリタイムアウトが発生しているような場合は、統計情報の自動更新がいつまでも完了せず、「毎回クエリ実行時に統計情報の更新が発生し、クエリタイムアウトになる」という状態となります。
このような状態となった場合、本来実行したいクエリの実行が、統計情報の更新により阻害された状態となります。
統計情報の同期的自動更新は完了したが、自動更新をトリガーしたクエリでクエリタイムアウトが発生
「2.」でクエリタイムアウトが発生した場合、統計情報の更新自体は完了している状態となります。
この場合、統計情報更新のトリガーとなったクエリでクエリタイムアウトが発生しても、統計情報が更新された状態は維持されているため、次回のクエリ実行時には統計情報の自動更新は発生せずに、クエリの実行が行われます。
統計情報の自動更新については「UpdateQPStats」というトランザクションで独立して実行されており、統計情報の更新のトリガーとなったクエリがタイムアウトしても、統計情報の更新自体はコミットされた状態が維持されます。
そのため、「2.」のケースでは統計情報の同期的更新は完了しており、以降のクエリ実行でタイムアウトが発生した場合、要因から統計情報の更新については除外することができ、問題の解決はトリガーとなったクエリに注視することができます。
まとめ
統計情報の同期的自動更新の実行中のクエリタイムアウトとしてはこのような事象が発生する可能性があることは覚えておくとよいのではないでしょうか。
SQL Server では、統計情報の非同期自動更新のオプション がありますので、統計情報の同期的自動更新で問題が発生した場合には、非同期の自動更新のオプションの有効化を検討してみてもよいのではないでしょうか。