○アプリケーションが実行するフェッチ処理が未完了の場合もテーブルがロックされたままである
クライアントアプリケーションはSQL Serverにクエリを送信したあと,すべての結果セットを取得しなければならない。もしアプリケーションが結果セットを取得できなければ,ロックはテーブルに残されたままである。たとえば,SQL Serverがクライアントに結果セットを送信し,クライアントアプリケーションがその結果セットを引き取るのを待っているときもロックされたままである。この状況は,プロセスがトランザクションのネストレベルが0(トランザクションがネスティングされていない状態)で「AWAITING COMMAND」に起因するsleeping状態にあるといえる。このような場合は,トランザクションのネストレベルが0(@@TRANCOUNT=0)で,spleeping状態にあるプロセスを調べる。あるいは,SQL Server Enterprise Managerを利用するのであれば,コンソールツリーから[管理]−[現在の利用状況]−[プロセス情報]をクリックしてプロセス一覧を表示し,[状態]列,[トランザクションを開く]列,[コマンド]列を調べる。[状態]列が「sleeping」,[トランザクションを開く]列が「0」,[コマンド]列が「AWAITING COMMAND」であれば,この原因が考えられる。この場合は,クライアントやネットワークが動作しているのか,およびクライアントアプリケーションが正しく設計されているのかを確認する必要がある。
○相手のいないコネクションである
ユーザーによっては,データベースサーバーからの応答があまりにも遅いと,自分のシステムがクラッシュしているものと勘違いしてクライアントを再起動させてしまうこともある。このような場合,データベースサーバーから見ると,そのコネクションは相手のいないコネクションとなってしまう。
相手のいないコネクションは,(1)クライアントアプリケーションでトラップが生じたとき,(2)クライアントが再起動されたとき,(3)クライアントが実際にクラッシュしたとき,などに発生する。このような場合,データベースサーバーはセッションをすぐにはキャンセルできないため,クライアントアプリケーションが獲得していたすべてのロックが残ってしまうことになり,ほかのアプリケーションからのロック要求をブロックしてしまうことになる。このような場合は,クライアントアプリケーションに応答の遅いクエリをキャンセルできるようなコードを書かなければならない。
○分散トランザクションの場合はロックの状態を検出できない
処理が停止しているとしても,必ずしもロックの解放待ちであるとは限らない。ネットワークI/Oの完了待ちである可能性もある。このような場合は,クエリタイムアウトを設定したり,sp_bindsessionシステムストアドプロシージャやsp_getbindtokenシステムストアドプロシージャを使用したりして,互いにブロックしない1つのトランザクションスペースにコネクションをバインドする。
○プロセスがロールバック状態にある
通常,ユーザーがトランザクションを強制終了した場合やキャンセルした場合は,ロールバックしなければならない。ロールバックは,クライアントが再起動された場合や,ネットワークが切断された場合にも実行される。さらに,デッドロックが発生したために強制的にSQL
Serverによって終了されたクエリも同様である。デッドロックによって強制終了されたプロセスをロールバックしているとき,ほかのプロセスはデータベースにアクセスすることができない。もしロールバックが完了しないうちにSQL
Serverがシャットダウンされ再起動されると,データベースは復旧モードとなり,自動復旧が完了する(コミットされていない変更がすべてロールバックされ,データベースの整合性が確保される)までデータベースにはアクセスできなくなる。このように,ロールバックの状態にあるプロセスを,SQL
Serverは「ロールバック状態」としてマークしている。ロールバック状態にあるあいだは,ほかのプロセスをブロックしている。プロセスがロールバック状態にあるか否かを調べるには,sp_whoシステムストアドプロシージャやSQL
Server Enterprise Managerなどを利用する。
ロックの問題を根本的に解決する方法はない。一般的には,サーバー側で長時間トランザクションをロックしているアプリケーションや長時間通信していないコネクションが存在しないかを監視し,存在した場合にはデータベース管理者にメッセージを送信するなど,運用で解決することになる。
SQL Serverのロック状況を確認するには,sp_lockシステムストアドプロシージャ,sp_whoシステムストアドプロシージャ,SQL
Server Enterprise Manager,パフォーマンスモニタ,DBCCステートメント,SQL
Serverプロファイラ,syslockinfoテーブルなどを用いる。
・sp_lockシステムストアドプロシージャによるロック状況の確認
sp_lockシステムストアドプロシージャを実行した場合には,Fig.9-42のように表示される。この例では,プロセス19の[Status]列が「WAIT」であり,行ロックの解放を待っていることがわかる。
Fig.9-42 sp_lockシステムストアドプロシージャの実行例
sp_lockシステムストアドプロシージャを実行したときに表示される各データ列は,次のような意味を備えている。
Table 9-2 sp_lockシステムストアドプロシージャで出力されるデータ列
データ列名 | 説明 |
spid | サーバープロセスID |
dbid | ロックを要求しているデータベースID |
ObjId | ロックを要求しているオブジェクトID |
IndId | インデックスID |
Type | ロックタイプ DB:データベース FIL:ファイル IDX:インデックス PG:ページ KEY:キー TAB:テーブル EXT:エクステント RID:行ID |
Resource | ロックリソースを示す。syslockinfo.restextの値と一致する |
Mode | ロック要求者のロックモードを示す S:共有ロック X:排他ロック U:更新ロック I:インテントロック Sch-S:スキーマ安定度ロック Sch-M:スキーマ修正ロック BU:一括更新ロック |
Status | ロック要求ステータスを示す。GRANT,WAIT,CNVRTの各モードがある |
Chapter 9 22/46 |