web-dev-qa-db-ja.com

SQL Serverでロックされたテーブルまたは行を検出する

ブロックされたセッションの詳細を追跡する方法を理解または学習しようとしています。

だから私は次の設定を作成しました:

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_lockssys.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で待機していることを確認します。

20

これはあなたが必要としていることだと思います。

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
23
James Anderson

あなたはそれを試すことができます :

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
3
Amin Attarzadeh