Dominando Locks: Identificando Transações Bloqueadas
30/12/2025 • Thiago Poderoso •
Dica
Um dos desafios mais comuns em ambientes de banco de dados é lidar com transações bloqueadas. Quando uma sessão adquire um lock em um recurso e outra sessão tenta acessar o mesmo recurso, ocorre um blocking que pode degradar significativamente a performance da aplicação.
Por que identificar locks é importante?
- Performance: Locks podem causar timeouts e aumentar a latência de consultas
- Concorrência: Ajuda a entender o padrão de acesso e conflitos entre transações
- Troubleshooting: Permite identificar quais queries estão causando bloqueios
- Otimização: Com essa informação, você consegue otimizar índices e ajustar a lógica das transações
A Query para SQL Server
Abaixo está uma query poderosa que fornece informações detalhadas sobre as sessões que estão bloqueando outras:
SELECT DES.Session_ID AS [Root Blocking Session ID], DER.STATUS AS [Blocking Session Request Status],
DES.Login_Time AS [Blocking Session Login Time], DES.Login_Name AS [Blocking Session Login Name],
DES.Host_Name AS [Blocking Session Host Name], Coalesce(DER.Start_Time, DES.Last_Request_Start_Time) AS [Request Start Time],
CASE WHEN DES.Last_Request_End_Time >= DES.Last_Request_Start_Time THEN DES.Last_Request_End_Time ELSE NULL END AS [Request End Time],
Substring(TEXT, DER.Statement_Start_Offset / 2, CASE WHEN DER.Statement_End_Offset = - 1 THEN DataLength(TEXT) ELSE DER.Statement_End_Offset / 2 END) AS [Executing Command],
CASE WHEN DER.Session_ID IS NULL THEN 'Blocking session does not have an open request and may be due to an uncommitted transaction.'
WHEN DER.Wait_Type IS NOT NULL THEN 'Blocking session is currently experiencing a ' + DER.Wait_Type + ' wait.'
WHEN DER.STATUS = 'Runnable' THEN 'Blocking session is currently waiting for CPU time.'
WHEN DER.STATUS = 'Suspended' THEN 'Blocking session has been suspended by the scheduler.'
ELSE 'Blocking session is currently in a ' + DER.STATUS + ' status.'
END AS [Blocking Notes]
FROM Sys.DM_Exec_Sessions DES(READUNCOMMITTED)
LEFT JOIN Sys.DM_Exec_Requests DER(READUNCOMMITTED) ON DER.Session_ID = DES.Session_ID
OUTER APPLY Sys.DM_Exec_Sql_Text(DER.Sql_Handle)
WHERE DES.Session_ID IN (SELECT Blocking_Session_ID
FROM Sys.DM_Exec_Requests(READUNCOMMITTED)
WHERE Blocking_Session_ID <> 0 AND Blocking_Session_ID
NOT IN (SELECT session_id
FROM Sys.DM_Exec_Requests(READUNCOMMITTED)
WHERE Blocking_Session_ID <> 0
)
);
O que cada coluna representa?
- Root Blocking Session ID: ID da sessão que está causando o bloqueio
- Blocking Session Request Status: Status atual da requisição (Running, Runnable, Suspended, etc)
- Login Name: Usuário que está executando a transação bloqueadora
- Host Name: Máquina de origem da conexão
- Request Start Time: Quando a transação começou
- Executing Command: O comando SQL que está sendo executado
- Blocking Notes: Descrição do status atual e tipo de wait
Dicas práticas
- Execute regularmente durante períodos de pico para identificar padrões
- Analise as queries bloqueadoras para oportunidades de otimização
- Considere usar índices nas colunas frequentemente usadas em WHERE e JOIN
- Revise transações longas que podem estar mantendo locks por muito tempo
- Use NOLOCK (READ UNCOMMITTED) com cuidado em consultas de leitura
Essa query é essencial no toolkit de qualquer DBA ou desenvolvedor que trabalha com SQL Server!