Hace algún tiempo que no publico en la sección de preguntas y respuestas. Pues la semana pasada me preguntaron. Cuál es la mejor forme de identificar bloqueos?
Pues esa pregunta puede tener varias respuestas, entre ellas las siguientes:
- Usar el Monitor de Actividad en el Management Studio
- Usar el procedimiento almacenado del sistema sp_who2, columna BlkBy
- Usar los reportes estándar de SQL Server
- Usar las vistas dinámicas sys.dm_tran_locks o sys.dm_exec_requests
Antes que nada, es importante aclarar que los bloqueos no son realmente un problema, siempre y cuando se mantenga controlados y no duren muchos segundos. Los bloqueos forman parte de los mecanismos que usa SQL Server para garantizar la concurrencia de usuarios y evitar que más de una transacción acceda al mismo tiempo a un mismo dato. Eso forma parte del concepto de Aislamiento, como parte de las características de una transacción.
En este vinculo pueden informarse sobre las características de una transacción: ACID
Regresando a la pregunta, yo particularmente prefiero usar las vistas dinámicas por que me dan la flexibilidad de usar consultas con T-SQL y obtener las columnas y filas que realmente necesito. Les propongo este script para consultar los bloqueos:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
SELECT DB_NAME(tl.resource_database_id) AS [BD], tl.request_mode AS [Tipo], tl.request_session_id AS [ID espera], h1.TEXT AS [Cmd espera], ec1.client_net_address AS [Equipo Espera], wt.blocking_session_id AS [ID bloquea], h2.TEXT AS [Cmd bloquea], ec2.client_net_address AS [Equipo Bloquea], OBJECT_NAME(p.OBJECT_ID) As [Objeto], tl.resource_type AS [Nivel Bloqueo], wt.wait_duration_ms/1000 AS [Segs] FROM sys.dm_tran_locks AS tl INNER JOIN sys.dm_os_waiting_tasks AS wt ON tl.lock_owner_address = wt.resource_address INNER JOIN sys.dm_exec_connections ec1 ON ec1.session_id = tl.request_session_id INNER JOIN sys.dm_exec_connections ec2 ON ec2.session_id = wt.blocking_session_id CROSS APPLY sys.dm_exec_sql_text(ec1.most_recent_sql_handle) AS h1 CROSS APPLY sys.dm_exec_sql_text(ec2.most_recent_sql_handle) AS h2 INNER JOIN sys.partitions AS p ON p.hobt_id = tl.resource_associated_entity_id |
Para poder mostrar resultados para esta consulta, simulé un bloqueo de la siguiente manera:
- Abrí una ventana de consultas en Management Studio y ejecuté la siguiente consulta, en la que a propósito he abierto una transacción sin el comando de cierre (COMMIT o ROLLBACK):
1 2 3 4 5 6 7 |
USE AdventureWorks2014 GO BEGIN TRAN UPDATE Person.Person SET Title = 'Mr' WHERE BusinessEntityID = 1 |
2. Luego abrí una segunda ventana de consultas en Management Studio y ejecuté la siguiente consulta, que intenta leer el registro que está asegurado o retenido por la transacción:
1 2 3 4 |
USE AdventureWorks2014 GO SELECT * FROM Person.Person WHERE BusinessEntityID = 1 |
Esto genera un bloqueo, el cual voy a identificar con la consulta mostrada líneas más arriba (He copiado el resultado a Excel para mejor visualización):
Aquí solo aparece una línea, y solo se va a capturar el bloqueo mientras este exista. Es decir, esta consulta no muestra una historia, si no información en línea y en tiempo real
Vínculos a temas relacionados: