クエリタイムアウト - その仕組み

神谷 雅紀
SQL Server Escalation Engineer

 

クエリタイムアウトまたはコマンドタイムアウト (Query Timeout/Command Timeout, 以降クエリタイムアウト)、使用するデータアクセスインタフェースにより呼び名は異なりますが、どちらも指定した時間が経過した後、実行中の処理を中断する機能です。

これらのタイムアウトに関して、「クライアントプログラムを変更せず、SQL Server データベースエンジン側の設定で、クエリタイムアウトを発生させないようにすることはできないか?」という質問を受けることがあります。答えは、「できない」です。その理由は、クエリタイムアウトは、クライアント側で動作するデータアクセスインタフェース (OLE DB プロバイダ、ODBC ドライバ、 SqlClient など) によって実装されている機能であるためです。SQL Server データベースエンジンは、クライアントからの要求に従い、実行中の処理をキャンセルするだけで、クエリタイムアウトのための時間計測は行っていません。

 

クエリの実行要求からクエリタイムアウトの発生までの流れ

 

  1. クライアントアプリケーションがデータアクセスインタフェースを通じて、SQL Server に対して何らかの処理の実行を要求します。例えば、SqlCommand.ExecuteNonQuery メソッドを呼び出し、クエリを実行します。
  2. データアクセスインタフェースは、その処理要求を SQL Server に送信すると同時にクエリタイムアウト時間を計測するためのタイマーをスタートさせます。
  3. 処理要求送信からの経過時間が、クエリタイムアウトとして指定されている時間経過しても、SQL Server から最初のパケットが送信されてこない場合、データアクセスインタフェースは、処理のキャンセル要求を SQL Server へ送信します。このキャンセル要求は、Attention (アテンション)  または Attention Signal (アテンションシグナル) と呼ばれます。 
  4. SQL Server は、Attention を受け取ると、そのクライアント接続を管理するデータ上で Attention ビットをオンにします。 
  5. そのクライアント接続上の処理を実行しているワーカースレッドは、定期的に Attention ビットがオンになっていないかどうかを確認しています。Attention ビットがオンになっていることを確認すると、自身が実行中の処理を中断します。

 

SQL Server データベースエンジン側でクエリタイムアウトの発生を知る方法

 

SQL Trace の Errors and Warnings カテゴリにある Attention イベントは、SQL Server がクライアントから Attention を受け取ったことを示すイベントです。 そのため、Attention イベントをトレースすることで、クライアントから実行中の処理のキャンセル要求があったことを知ることができます。実行中のクライアントアプリケーションが、Management Studio にあるような処理キャンセル機能をユーザに提供していない場合、「Attention イベントの発生 = クエリタイムアウトの発生」です。クエリのキャンセル機能をユーザに提供している業務アプリケーションは多くないため、ほとんどの場合、「Attention イベントの発生 = クエリタイムアウトの発生」です。

しかし、Attention 自体は、前述のとおり、アプリケーションが明示的にキャンセルを要求した場合、例えば、SqlCommand.Cancel メソッドが呼び出された場合にも、SQL Server に対して送信されるため、SQL Server の観点からは、受け取った Attention がクエリタイムアウトの結果として送信されてきたものなのか、アプリケーションが明示的にキャンセルを要求したために送信されてきたものなのかを区別することはできません。 そのため、クエリタイムアウトの発生を厳密に捉えようとした場合には、クライアントアプリケーションにクエリタイムアウトの発生を記録する仕組みを実装することが必要です。