ブロックされたセッションの詳細を追跡する方法を理解または学習しようとしています。
だから私は次の設定を作成しました:
create table foo (id integer not null primary key, some_data varchar(20));
insert into foo values (1, 'foo');
commit;
次に、2つの異なるクライアントからデータベースに2回接続します。
最初のセッションの問題:
begin transaction
update foo set some_data = 'update'
where id = 1;
私は明示的にnotをコミットして、ロックを保持します。
2番目のセッションでは、同じステートメントを発行します。もちろん、ロックのために待機します。現在、セッション2がfoo
テーブルを待機していることを確認するために、さまざまなクエリを使用しています。
sp_who2
は以下を示しています(重要な情報のみを表示するために一部の列を削除しました)。
SPID |ステータス| BlkBy | DBName |コマンド| SPID | REQUESTID ----- + -------------- + ------- + ---------- + ---- -------------- + ------ + ---------- 52 |寝る| 。 | foodb | AWAITINGコマンド| 52 | 0 53 |寝る| 。 | foodb | AWAITINGコマンド| 53 | 0 54 | SUSPENDED | 52 | foodb |更新| 54 | 0 56 | RUNNABLE | 。 | foodb | SELECT INTO | 56 | 0
これは予想されることであり、セッション54は、セッション52からのコミットされていない変更によってブロックされます。
sys.dm_os_waiting_tasks
のクエリでもこれがわかります。ステートメント:
select session_id, wait_type, resource_address, resource_description
from sys.dm_os_waiting_tasks
where blocking_session_id is not null;
戻り値:
session_id | wait_type | resource_address | resource_description ----------- + ----------- + -------------------- + ------------------------------------------------- -------------------------------- 54 | LCK_M_X | 0x000000002a35cd40 | keylock hobtid = 72057594046054400 dbid = 6 id = lock4ed1dd780 mode = X associatedObjectId = 72057594046054400
再びこれは予想されます。
私の問題は、セッション54が待機している実際のオブジェクト名を見つける方法がわからないことです。
次のように、sys.dm_tran_locks
とsys.dm_os_waiting_tasks
を結合するクエリがいくつか見つかりました。
SELECT ....
FROM sys.dm_tran_locks AS l
JOIN sys.dm_os_waiting_tasks AS wt ON wt.resource_address = l.lock_owner_address
しかし、上記のテストシナリオでは、この結合は何も返しません。したがって、その結合が間違っているか、dm_tran_locks
に実際に探している情報が含まれていません。
だから私が探しているのは次のようなものを返すクエリです:
"セッション54はテーブルfoo
のロックを待機しています"。
背景情報:
私が解決しようとしている実際の問題はもう少し複雑ですが、「どのテーブルがセッション54を待っているのか」という質問に要約されます。問題の問題には、いくつかのテーブルを更新する大量のストアドプロシージャと、それらのテーブルの一部にアクセスするビューからの選択が含まれます。スナップショット分離とコミットされた読み取りスナップショットが有効になっている場合でも、select
ステートメントはブロックされます。選択がブロックされている理由を把握すること(スナップショット分離が有効になっている場合は不可能だと考えていました)が次のステップです。
最初のステップとして、そのセッションがwhatで待機していることを確認します。
これはあなたが必要としていることだと思います。
USE 'yourDB'
GO
SELECT
OBJECT_NAME(p.[object_id]) BlockedObject
FROM sys.dm_exec_connections AS blocking
INNER JOIN sys.dm_exec_requests blocked
ON blocking.session_id = blocked.blocking_session_id
INNER JOIN sys.dm_os_waiting_tasks waitstats
ON waitstats.session_id = blocked.session_id
INNER JOIN sys.partitions p ON SUBSTRING(resource_description,
PATINDEX('%associatedObjectId%', resource_description) + 19,
LEN(resource_description)) = p.partition_id
あなたはそれを試すことができます :
SELECT
db_name(rsc_dbid) AS 'DATABASE_NAME',
case rsc_type when 1 then 'null'
when 2 then 'DATABASE'
WHEN 3 THEN 'FILE'
WHEN 4 THEN 'INDEX'
WHEN 5 THEN 'TABLE'
WHEN 6 THEN 'PAGE'
WHEN 7 THEN 'KEY'
WHEN 8 THEN 'EXTEND'
WHEN 9 THEN 'RID ( ROW ID)'
WHEN 10 THEN 'APPLICATION' end AS 'REQUEST_TYPE',
CASE req_ownertype WHEN 1 THEN 'TRANSACTION'
WHEN 2 THEN 'CURSOR'
WHEN 3 THEN 'SESSION'
WHEN 4 THEN 'ExSESSION' END AS 'REQUEST_OWNERTYPE',
OBJECT_NAME(rsc_objid ,rsc_dbid) AS 'OBJECT_NAME',
PROCESS.HOSTNAME ,
PROCESS.program_name ,
PROCESS.nt_domain ,
PROCESS.nt_username ,
PROCESS.program_name ,
SQLTEXT.text
FROM sys.syslockinfo LOCK JOIN
sys.sysprocesses PROCESS
ON LOCK.req_spid = PROCESS.spid
CROSS APPLY sys.dm_exec_sql_text(PROCESS.SQL_HANDLE) SQLTEXT