SQL Serverでデッドロックの調査で苦労したので調査に使ったSQLなどをまとめておく。
SQL Serverにおいては、ロックの有無を確認するだけならsys.dm_tran_locksシステムビューですぐに確認できる。
SELECT * FROM sys.dm_tran_locks
しかし、sys.dm_tran_locksだけでは、テーブルロックや行ロックなどの情報がまとめて提供され、ロックされている対象も
オブジェクトIDでの表記になるため非常にわかりにくいものになっています。
ですので、単純にSELECTするのではなく、IDからオブジェクト名を取得したり、オブジェクトの種類によって
別のシステムビューから情報を取得する必要があります。
手を加えたSQLが以下のようになります。
SELECT
resource_type AS type --オブジェクトの種類
,resource_associated_entity_id as entity_id --エンティティID
,( CASE WHEN resource_type = 'OBJECT' THEN
OBJECT_NAME( resource_associated_entity_id )
ELSE
( SELECT
OBJECT_NAME( OBJECT_ID )
FROM
sys.partitions
WHERE
hobt_id=resource_associated_entity_id )
END)
AS object_name
,request_mode --ロックの種類
,request_type --要求の種類
,request_status --状態
,request_session_id AS Session_id --セッションID
,(SELECT hostname
FROM sys.sysprocesses
WHERE spid = request_session_id) AS ProcessName
FROM
sys.dm_tran_locks
WHERE
resource_type <> 'DATABASE'
ORDER BY
request_session_id
実行結果は以下のようになります。
他に必要な項目がある場合、SELECT文へ項目の追加を行ってください。
主なロックステータスの種類
主なロックステータスの種類として以下のものがあります。
| S | 共有ロック | 他のトランザクションからの読込は可能。更新は不可となる。 |
| X | 排他ロック |
他のトランザクションからの読込・更新が共に不可となる。 INSERT、UPDATE、DELETEを実行するとこのロックになる。 |
| U | 更新ロック |
他のトランザクションからの読込は可能。更新は不可となる。 SELECTで WITH( UPDLOCK )を指定するとこのロックになる。 |
使用したシステムビューについて
・sys.dm_tran_locks・・・ロック情報を参照できるビュー。
ビュー詳細情報<Micrsoft MSDN>
・sys.partitions・・・テーブルまたはインデックスで使用されているパーティション情報を参照できるビュー。
ビュー詳細情報<Micrsoft MSDN>
・sys.sysprocesses・・・接続されているProcess情報を参照できるビュー。
ビュー詳細情報<Micrsoft MSDN>
ロックエラーをわざと発生させる方法
異常系のテストを行いたい場合などで、テーブルのロックをかけたい場合の手順。
・以下のロック用SQLを実行(sleepしている間ロックされている)
BEGIN TRAN
SELECT * FROM TABLEA WITH(TABLOCKX)
WAITFOR DELAY '00:01:00' --任意の時間スリープ。
COMMIT TRAN
※SSMS(SQL Server Management Studio)などでデバッグ実行できるなら、
COMMIT TRANまでにブレークしておけばよい。
・エラーを起こすSQL
SET LOCK_TIMEOUT 0 SELECT * FROM TABLEA
⇒ロックタイムアウトの値を0にしているため、即時ロックエラーになる。