Consultar o sys.dm_tran_locks
DMV nos mostra quais sessões (SPIDs) estão mantendo bloqueios em recursos como tabela, página e linha.
Para cada bloqueio adquirido, existe alguma maneira de determinar qual instrução SQL (excluir, inserir, atualizar ou selecionar) causou esse bloqueio?
Eu sei que a most_recent_query_handle
coluna do sys.dm_exec_connections
DMV nos dá o texto da última consulta executada, mas várias vezes outras consultas foram executadas antes na mesma sessão (SPID) e ainda estão mantendo bloqueios.
Já utilizo o sp_whoisactive
procedimento (de Adam Machanic) e ele mostra apenas a consulta que está no buffer de entrada no momento (pense DBCC INPUTBUFFER @spid
), que nem sempre (e no meu caso geralmente nunca) é a consulta que adquiriu o bloqueio.
Por exemplo:
- abrir transação/sessão
- exec uma instrução (que mantém um bloqueio em um recurso)
- exec outra instrução na mesma sessão
- abra outra transação/sessão e tente modificar o recurso bloqueado na etapa 2.
O sp_whoisactive
procedimento apontará a instrução na etapa 3, que não é a responsável pelo bloqueio e, portanto, não é útil.
Essa pergunta surgiu ao fazer uma análise usando o recurso Blocked Process Reports , para encontrar a causa raiz dos cenários de bloqueio na produção. Cada transação executa várias consultas e, na maioria das vezes, a última (que é mostrada no buffer de entrada no BPR) raramente é a que mantém o bloqueio.
Eu tenho uma pergunta de acompanhamento: Estrutura para identificar efetivamente as consultas de bloqueio
O SQL Server não mantém um histórico dos comandos que foram executados 1,2 . Você pode determinar quais objetos têm bloqueios, mas não pode necessariamente ver qual instrução causou esses bloqueios.
Por exemplo, se você executar esta instrução:
E olhe para o Texto SQL através do identificador sql mais recente, você verá que a instrução aparece. No entanto, se a sessão fez isso:
Você só veria a
SELECT * FROM dbo.TestLock;
instrução, mesmo que a transação não tenha sido confirmada e aINSERT
instrução esteja bloqueando os leitores nadbo.TestLock
tabela.Eu uso isso para procurar transações não confirmadas que estão bloqueando outras sessões:
Se configurarmos um banco de teste simples no SSMS com algumas janelas de consulta, podemos ver que só podemos ver a instrução ativa mais recente.
Na primeira janela de consulta, execute isto:
Na segunda janela, execute isto:
Agora, se executarmos a consulta de transações de bloqueio não confirmadas acima, veremos a seguinte saída:
(Removi algumas colunas irrelevantes do final dos resultados).
Agora, se alterarmos a primeira janela de consulta para isso:
e execute novamente a 2ª janela de consulta:
Veremos esta saída da consulta de transações de bloqueio:
1 - não inteiramente verdade. Existe o cache de procedimento, que pode conter a instrução responsável pelo bloqueio. No entanto, pode não ser fácil determinar qual instrução é a causa real do bloqueio, pois pode haver muitas consultas no cache que tocam no recurso em questão.
A consulta abaixo mostra o plano de consulta para as consultas de teste acima, pois meu cache de procedimento não está muito ocupado.
Os resultados desta consulta podem permitir que você encontre o culpado, mas esteja ciente, inspecionar o cache de procedimento como este pode ser bastante exigente em um sistema ocupado.
2 SQL Server 2016 e superior oferecem o Query Store , que retém o histórico completo das consultas executadas.
Para complementar a outra resposta , achei os utilitários abaixo extremamente úteis:
Eu uso o beta_lockinfo quando quero me aprofundar no bloqueio e analisar o que e como o bloqueio surgiu - o que é extremamente útil.