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.


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

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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.