Detectar la tabla o fila bloqueada en SQL Server


20

Estoy tratando de entender / aprender cómo rastrear los detalles de una sesión bloqueada.

Entonces creé la siguiente configuración:

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

Ahora me conecto a la base de datos dos veces desde dos clientes diferentes.

Los problemas de la primera sesión:

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

No me comprometo explícitamente allí para mantener los bloqueos.

En la segunda sesión, emito la misma declaración y, por supuesto, esa espera debido al bloqueo. Ahora estoy tratando de usar las diferentes consultas que flotan para ver que la sesión 2 está esperando la footabla.

sp_who2 muestra lo siguiente (eliminé algunas columnas para mostrar solo la información importante):

SPID | Estado | BlkBy | DBName | Comando | SPID | SOLICITUD
----- + -------------- + ------- + ---------- + ---------- -------- + ------ + ----------
52 | durmiendo | . El | foodb | ESPERANDO MANDO | 52 | 0 0        
53 durmiendo | . El | foodb | ESPERANDO MANDO | 53 0 0        
54 Suspendido | 52 | foodb | ACTUALIZAR | 54 0 0        
56 RUNNABLE | . El | foodb | SELECCIONAR EN | 56 0 0        

Esto se espera, la sesión 54 está bloqueada por los cambios no confirmados de la sesión 52.

La consulta sys.dm_os_waiting_taskstambién muestra esto. La declaración:

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

devoluciones:

session_id | wait_type | direccion_recursos | recurso_descripción                                                            
----------- + ----------- + -------------------- + ----- -------------------------------------------------- --------------------------
        54 LCK_M_X | 0x000000002a35cd40 | tecla de bloqueo hobtid = 72057594046054400 dbid = 6 id = lock4ed1dd780 mode = XsociatedObjectId = 72057594046054400

De nuevo, esto se espera.

Mi problema es que no puedo encontrar la forma de encontrar el nombre real del objeto que la sesión 54 está esperando.

He encontrado varias consultas que se están uniendo sys.dm_tran_locksy sys.dm_os_waiting_tasksasí:

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

Pero en mi escenario de prueba anterior, esta unión no devuelve nada. Entonces, esa unión está mal o en dm_tran_locksrealidad no contiene la información que estoy buscando.

Entonces, lo que estoy buscando es una consulta que devuelva algo como:
"la sesión 54 está esperando un bloqueo en la tablafoo ".


Alguna información de fondo:

El problema de la vida real que estoy tratando de resolver es un poco más complicado, pero se reduce a la pregunta "en qué mesa está esperando la sesión 54". El problema en cuestión implica un procedimiento almacenado muy grande que actualiza varias tablas y una selección desde una vista que accede a algunas de esas tablas. La selectdeclaración está bloqueada a pesar de que tenemos habilitado el aislamiento de la instantánea y la lectura de la instantánea confirmada. Averiguar por qué la selección está bloqueada (lo que pensé que no sería posible si se habilita el aislamiento de instantáneas) será el siguiente paso.

Como primer paso, me gustaría saber qué espera esa sesión.



@MaxVernon: gracias por confirmar eso. Pero entonces estoy aún más confundido. ¿Por qué no devuelve nada aunque sé que hay un bloqueo y una sesión bloqueada?
a_horse_with_no_name

No puedo recrear el problema que está viendo en SQL Server 2012. Creé una base de datos de prueba, habilité RCSI, creé sus tablas y ejecuté ambas declaraciones de actualización, y veo una fila devuelta por su última consulta.
Max Vernon

Si desea una ayuda visual para detectar sus bloqueos, hay una herramienta de código abierto disponible llamada buscador de bloqueos SQL. Puede encontrar la fuente en: github.com/LucBos/SqlLockFinder O descargue el ejecutable en: sqllockfinder.com También nos encantan las contribuciones que pueda hacer al código para que podamos mejorarlo.
Luc Bos

Respuestas:


23

Creo que esto hace lo que necesitas.

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

Puedes probarlo :

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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.