9.7.1 ロック
トランザクションが実行されている環境下で性能が低下する原因の1つとして,使用しようとしているリソースがロックされている場合がある。アプリケーションは,トランザクションを処理するにあたって,行やページまたはテーブルをロックする。このとき,長時間にわたってロックを維持すると,ほかのアプリケーションのトランザクション処理をブロックしてしまうことになる。このような場合には,トランザクション処理をコミットする単位をできるだけ小さくすることが必要になる。たとえば,クエリが長時間にわたってロックを維持すると考えられるのは,次のような場合である。
○実行時間の長いクエリ
実行時間の長いクエリを識別する方法は,すでに「9.6.1 「遅いクエリ」の識別」で述べたとおり,SQL Serverプロファイラを利用して,開始時刻の最も古いトランザクションを探せばよい。しかし,その場合,SQL
Serverプロファイラでトレースの採取を開始しておく必要がある。あらかじめSQL
Serverプロファイラを起動していなくても,長時間にわたって稼働しているトランザクションの有無は,DBCC
OPENTRANステートメントで調査することができる。DBCC
OPENTRANステートメントの構文は次のとおりである。
DBCC OPENTRAN(database_name | database_id)
このステートメントを利用すると,最も古いアクティブなトランザクションの情報が表示されるので,タイムスタンプと開始時刻を検証する。予想される時間よりも長時間にわたって稼働している(たとえば30分以上とか1時間以上)場合には,トランザクションをキャンセルする。DBCC OPENTRANステートメントを実行すると,次のような結果が表示される。
Fig.9-39 DBCC OPENTRANステートメントの実行結果
もしこれがレプリケーションのトランザクションであれば,Fig.9-39のメッセージに続いて,さらに次のようなメッセージが表示される。
レプリケートされたトランザクション情報 | : |
配布された最も古いLSN | : (32:314:1) |
配布されなかった最も古いLSN : | : (0:0:0) |
○プロセスがsleeping状態にある
アプリケーションのプロセスがsleeping状態になる原因はいくつかある。通常,クエリをサーバーに送信すると,アプリケーションは結果セットが戻るのを待っている。また,サーバー上のアプリケーションは,リソースに対して処理を要求し,その完了を待っている。
このような待ち状態にあるアプリケーションプロセスは,I/O完了待ち(Windows
NT APIコールの応答待ち)の状態ステータスとしてsleeping状態になっている(I/Oが完了して起こされるまで寝てしまっている)。あるいは,プロセス(たとえばサーバープロセス)がほかのプロセス(たとえばクライアントアプリケーションプロセス)からの要求を待っている場合やタイマで時間がくるのを待っている場合にも,sleeping状態になる。すなわち,アプリケーションプロセスが何かのイベント(I/O完了,要求,時間など)待ちにあるときは,プロセスの状態としてsleeping状態となっている。
このような状況下におけるロックの問題とは,アプリケーションの設計に起因するものである。たとえば,BEGIN
TRANステートメントに対して必要な数のROLLBACKステートメントやCOMMITステートメントが実行されないままクライアントのアプリケーションがキャンセルされたり,終了されたりすると,トランザクションがロールバックもコミットもされないまま残されてしまう。すると,SQL
Server側では,完全に完了していないサーバープロセス(キャンセルされたクライアントアプリケーションに対応するワーキングスレッド)として,sleeping状態のままクライアントからのROLLBACKステートメントやCOMMITステートメントを待つことになる。このようなsleeping状態のプロセスでは,UPDATEステートメントやDELETEステートメントを実行するためにリソースに対して課していたロックもそのままの状態で維持されており,ほかのプロセスによるアクセスをブロックしてしまう。
ROLLBACKステートメントやCOMMITステートメントの実行待ちでプロセスがsleeping状態にあるか否かは,トランザクションのネストレベル(@@TRANCOUNT*1>0)やSQL Server Enterprise Managerなどを利用して調べることができる。SQL
Server Enterprise Managerを利用する場合は,コンソールツリーから[管理]−[現在の利用状況]を展開し,[プロセス情報]をクリックする。すると,詳細ペインにプロセス一覧が表示されるので,[状態]列を調べる。
Fig.9-40 トランザクションを開いたままsleeping状態にあるプロセス(クリックで拡大)
Fig.9-40の場合,プロセス21の[状態]列が「sleeping」である。このプロセスの[トランザクションを開く]列は「1」,[コマンド]列は「AWAITING COMMAND」(コマンド待ち)となっている。このプロセスは,BEGIN TRANステートメントに対して必要な数のROLLBACKステートメントやCOMMITステートメントが実行されずにクエリがキャンセルされた例である。プロセス21をダブルクリックして[プロパティ]ダイアログボックスを表示させると,最後に実行されたステートメントあるいはバッチが表示される。この場合は,COMMITステートメントがないバッチが実行されている。 [プロセス情報]を選択した場合には,次のような情報が表示される。
Table 9-1 プロセス一覧に表示される情報
列名 | 説明 |
SPID | ユーザーアプリケーションに対応するサーバープロセスIDを示す |
ユーザー | ログインIDを示す。システムプロセスの場合はsystemである |
データベース | プロセスがアクセスしているデータベース名を示す |
状態 | サーバープロセスの状態を示す |
トランザクションを開く | 現在アクティブなトランザクション数を示す |
コマンド | プロセスが実行しているコマンドを示す。[状態]列が「sleeping」であれば,その理由を示す |
アプリケーション | ユーザーアプリケーション名を示す |
待機時間 | イベント発生の待ち時間を示す |
待機の種類 | 待機の理由を示す |
リソースの待機 | 待機しているリソースを示す |
CPU | プロセッサの累積使用時間を示す |
物理I/O | 物理ディスクへの累積I/O回数を示す |
メモリ使用量 | メモリの使用容量を示す |
ログイン日時 | ユーザーがログインした日時を示す |
最後のバッチ | 最後に実行されたバッチを示す |
ホスト | クライアントのコンピュータ名を示す |
ネットワークライブラリ | クライアントが利用しているネットワークライブラリの種類を示す |
ネットワークアドレス | クライアントのネットワークアドレスを示す |
ブロックしている | このプロセスをブロックしているプロセスIDを示す |
ブロッキング | このプロセスがブロックしているプロセスIDを示す |
*26: 現在の接続に対してアクティブなトランザクションの数を返す関数。
COLUMN | ||
プロセスの情報を表示したユーザーは,そのプロセスに問題があれば,その状況をメッセージとしてシステム管理者に送信することができる。そのためには,プロセス情報を表示しているときにプロセスを右クリックすると表示されるメニューから[メッセージ送信]を選択すると,管理者にメッセージを送信できる。たとえば,次の図に示すように「プロセスがストールしている。」というメッセージを送信できる。 Fig.9-41 メッセージの送信画面(上)と受信画面(下) |
Chapter 9 21/46 |