Detectando a tabela ou linha bloqueada no SQL Server

20

Estou tentando entender / aprender a rastrear os detalhes de uma sessão bloqueada.

Então, eu criei a seguinte configuração:

create table foo (id integer not null primary key, some_data varchar(20));
insert into foo values (1, 'foo');
commit;

Agora eu me conecto ao banco de dados duas vezes de dois clientes diferentes.

A primeira sessão emite:

begin transaction
update foo set some_data = 'update'
  where id = 1;

Eu explicitamente não confirmo lá para manter os bloqueios.

Na segunda sessão, emito a mesma declaração e, é claro, que se espera devido ao bloqueio. Agora estou tentando usar as diferentes consultas flutuando para ver se a sessão 2 está aguardando a footabela.

sp_who2 mostra o seguinte (removi algumas colunas para mostrar apenas as informações importantes):

SPID Status BlkBy | DBName | Comando SPID IDENTIFICAÇÃO DO PEDIDO
----- + -------------- + ------- + ---------- + ---------- -------- + ------ + ----------
52 dormindo | . | foodb | AGUARDANDO COMANDO | 52 0 0        
53 dormindo | . | foodb | AGUARDANDO COMANDO | 53 0 0        
54 SUSPENSO | 52 foodb | ATUALIZAÇÃO | 54 0 0        
56 RUNNABLE | . | foodb | SELECIONAR EM | 56 0 0        

Isso é esperado, a sessão 54 é bloqueada pelas alterações não confirmadas da sessão 52.

A consulta sys.dm_os_waiting_taskstambém mostra isso. A declaração:

select session_id, wait_type, resource_address, resource_description
from sys.dm_os_waiting_tasks
where blocking_session_id is not null;

retorna:

session_id | wait_type | resource_address | resource_description                                                            
----------- + ----------- + -------------------- + ----- -------------------------------------------------- --------------------------
        54 LCK_M_X 0x000000002a35cd40 | hobtid do bloqueio do teclado = 72057594046054400 dbid = 6 id = modo lock4ed1dd780 = X AssociatedObjectId = 72057594046054400

Novamente, isso é esperado.

Meu problema é que não consigo descobrir como encontrar o nome real do objeto que a sessão 54 está aguardando.

Eu encontrei várias consultas que estão ingressando sys.dm_tran_lockse sys.dm_os_waiting_tasksassim:

SELECT ....
FROM sys.dm_tran_locks AS l
  JOIN sys.dm_os_waiting_tasks AS wt ON wt.resource_address = l.lock_owner_address

Mas no meu cenário de teste acima, essa junção não retorna nada. Portanto, essa junção está errada ou dm_tran_locksnão contém as informações que estou procurando.

Então, o que estou procurando é uma consulta que retorne algo como:
"a sessão 54 está aguardando um bloqueio na tabelafoo ".


Algumas informações básicas:

O problema da vida real que estou tentando resolver é um pouco mais complicado, mas resume-se à pergunta "em que mesa está aguardando a sessão 54". O problema em questão envolve um procedimento armazenado amplo que atualiza várias tabelas e uma seleção de uma exibição que acessa algumas dessas tabelas. A selectinstrução está bloqueada, apesar de termos o isolamento da captura instantânea e a leitura da captura instantânea confirmada ativada. Descobrir por que a seleção está bloqueada (o que eu pensei que não seria possível se o isolamento de captura instantânea estiver ativado) será o próximo passo.

Como primeiro passo, gostaria de descobrir o que a sessão está esperando.

um cavalo sem nome
fonte
msdn.microsoft.com/en-us/library/ms190345.aspx diz que sua associação está correta.
Max Vernon
@ MaxVernon: obrigado por confirmar isso. Mas então eu estou ainda mais confuso. Por que ele não retorna nada, embora eu saiba que há um bloqueio e uma sessão bloqueada?
precisa saber é o seguinte
Não consigo recriar o problema que você está vendo no SQL Server 2012. Criei um banco de dados de teste, habilitei o RCSI, criei suas tabelas e executei as duas instruções de atualização e vejo uma linha retornada por sua última consulta.
Max Vernon
Se você deseja uma ajuda visual na detecção de seus bloqueios, existe uma ferramenta de código aberto disponível chamada SQL Lock Finder. Você pode encontrar a fonte em: github.com/LucBos/SqlLockFinder Ou faça o download do executável em: sqllockfinder.com Também gostamos de qualquer contribuição que você possa fazer no código para que possamos melhorá-lo.
Luc Bos

Respostas:

23

Eu acho que isso faz o que você precisa.

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
James Anderson
fonte
3

Você pode experimentá-lo :

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