Microsoft SQL Server/Microsoft Azure SQL Database サポートチーム
サポート エスカレーション エンジニア 高原 伸城
皆さん、こんにちは。 Microsoft SQL Server/Microsoft Azure SQL Database サポートチーム です。
今回は、Microsoft Azure SQL Database (以下 MASD) のパフォーマンス チューニング手法について紹介します。
MASD 上のデータベースに対して、アプリケーション から クエリを実行し、コマンドタイムアウトが発生したという現象についてお問い合わせを頂くことがあります。
コマンドタイムアウトが発生した場合は、一般的に、以下の項目について確認する必要があります。
[確認項目] 1) コマンドタイムアウトで失敗したクエリの特定 2) 該当クエリの実行プランの確認 3) ブロッキングの発生有無 4) リソースの使用状況 (パフォーマンス レベル (DTU) 以上の処理が実行されていないかの確認) |
そして、コマンドタイムアウトが発生している状況に応じた対処方法を検討する必要があります。
しかしながら、コマンドタイムアウトが発生したクエリを特定し、クエリのチューニングを実施することは、一般的に時間を要する作業となります。
そのため、今回のブログでは、コマンドタイムアウトが多発し、即座に問題を緩和させる必要がある場合 に、まずは試して欲しい対処方法を紹介します。
※ 一般的に、データセンター側の問題でクエリの処理時間が著しく低下する現象は発生しないため、今回は確認項目から省いています。
[対処方法]
1) アプリケーション側で指定しているコマンドタイムアウト値を延ばす。
+ 参考情報
SqlCommand.CommandTimeout プロパティ
EntityCommand.CommandTimeout プロパティ
2) インデックスの統計情報を更新する。
コマンドタイムアウトが発生しているクエリが参照しているテーブル上に存在するインデックスの統計情報を最新の状態に更新することで、最適なクエリの実行プランが選択されるようになり、クエリのパフォーマンスが向上できることが期待できます。
そして、”UPDATE STATISTICS” コマンドを実行することで、インデックスの統計情報 (テーブル上に存在する全てのインデックス、特定のインデックス) を更新することが可能です。
”UPDATE STATISTICS” コマンドでオプションをつけない場合は、一部のデータをサンプリングしてインデックスの統計情報が更新されます。 また オプション (WITH FULLSCAN) を付けることで、テーブル上に存在する全てのデータをもとに統計情報を更新することも可能です。
もちろん全てのデータをもとに更新する方がより正確なインデックスの統計データを作成することが可能ですが、データページの読み取りなどのディスク I/O、CPU リソースが多く消費されることが予測されます。
そのため、データ量の多いテーブルに対して ”UPDATE STATISTICS” コマンドを実行する場合は、まずは オプション無し (サンプリング) よる統計情報の更新を実行後、効果が見られない場合に オプション (WITH FULLSCAN) で再度実行してみましょう。
– テーブル tab1 に存在する全てのインデックスの統計情報を更新 – テーブル tab1 に存在する特定のインデックス (本例では PK_tab1) の統計情報を更新
– テーブル tab1 に存在する全てのインデックスの統計情報を更新 (フルスキャン) – テーブル tab1 に存在する特定のインデックス (本例では PK_tab1) の統計情報を更新 (フルスキャン) |
+ 参考情報
UPDATE STATISTICS (Transact-SQL)
3) 強制的に実行プランをリコンパイルする。
パラメータ化クエリ、 ストアドプロシージャ 及び トリガー の場合、統計情報を更新したのみでは、クエリの実行プランが リコンパイル されない場合があります。
そのため、統計情報を更新した後もクエリのパフォーマンスが改善しなかった場合には、明示的に該当の パラメータ化クエリ、 ストアドプロシージャ 及び トリガー に対して “sp_recompile” を実行し、強制的にクエリの実行プランをリコンパイルさせることが有効となる場合があります。
また、どのクエリでパフォーマンスが低下しているかが明確ではないが、クエリで参照されているテーブルをある程度 特定できる場合は、特定のテーブルに対して実行されるクエリをすべて強制的にリコンパイルさせることも可能です。
– 特定のストアドプロシージャ (本例では sp_TEST1) を強制的にリコンパイルさせる。 – テーブル tab1 を参照するすべてのクエリを強制的にリコンパイルさせる。 |
+ 参考情報
[補足]
アプリケーションで発生しているタイムアウトがコマンドタイムアウトであるかを確認する方法の一つとして、タイムアウト発生時にクライアント側に返された スタック (Stack) 情報を確認する方法があります。
System.Data.SqlClient.SqlCommand の処理の中でタイムアウトが発生した場合は、コマンドタイムアウトが発生していると判断可能となります。
### コマンドタイムアウト発生時の Stack 例 ###
System.Data.SqlClient.SqlException:Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding. .. .
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection,…) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj,…) at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler,… ) at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, …) at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, …) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, …) at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion,…) at System.Data.SqlClient.SqlCommand.ExecuteNonQuery() : |
Microsoft Azure SQL Database パフォーマンス チューニング (第 2 回) では、リソースの使用状況の確認方法、及び パフォーマンス レベル (DTU) の変更方法などを紹介する予定です。
※ 本Blogの内容は、2016年5月 現在の内容となっております。