Síntomas comunes

  • La aplicación muestra el error "Transaction (Process ID X) was deadlocked on lock resources"
  • Operaciones que normalmente toman segundos quedan suspendidas indefinidamente
  • sys.dm_exec_requests muestra sesiones con blocking_session_id > 0 y wait_type = 'LCK_M_X' o similar
  • Usuarios reportan timeouts aleatorios que se resuelven solos después de varios segundos
  • Las métricas de monitoreo muestran spikes en LCK_M_X o LCK_M_U en wait stats

Riesgos para el negocio

  • Transacciones de negocio abortadas por deadlock generan datos inconsistentes si la aplicación no reintenta correctamente
  • Bloqueos en cascada pueden paralizar decenas de sesiones simultáneamente
  • Una sesión bloqueante con una transacción larga puede bloquear a toda la concurrencia de una tabla crítica
  • Deadlocks frecuentes indican un problema de diseño que empeora con el crecimiento de la carga

Checklist técnico detallado

  • 1. Identificar la cabeza de la cadena de bloqueos La sesión raíz es la que tiene blocking_session_id = 0 pero otras sesiones la apuntan como bloqueante. Es la que debe resolverse.
  • 2. Leer deadlocks desde la sesión system_health (sin configuración extra) SQL Server 2012+ captura deadlocks automáticamente en el Extended Event system_health.
  • 3. Verificar si RCSI está habilitado RCSI elimina los bloqueos entre lectores y escritores sin cambiar código de la aplicación.
  • 4. Habilitar RCSI si no está activo Requiere acceso exclusivo momentáneo. Ejecutar con cuidado en producción, idealmente en ventana de mantenimiento.
  • 5. Revisar transacciones abiertas sin actividad (idle in transaction) Una transacción que no se cerró correctamente puede mantener locks durante horas.
  • 6. Terminar manualmente una sesión bloqueante si es seguro Solo si la sesión bloqueante es inactiva y el negocio lo requiere. Verificar primero qué transacción tiene abierta.
  • 7. Configurar Blocked Process Report para alertas automáticas Activa una alerta cuando una sesión lleva más de N segundos bloqueada.
  • 8. Revisar el nivel de aislamiento de las transacciones más frecuentes READ COMMITTED (por defecto) puede generar bloqueos lector-escritor. SNAPSHOT o RCSI los eliminan.

Estrategias de prevención a largo plazo

Los bloqueos recurrentes generalmente tienen causas estructurales que se deben atacar en el código y en la configuración:

  • Habilitar RCSI: elimina bloqueos lector-escritor sin cambiar código. Es la mejora más impactante en la mayoría de los casos.
  • Reducir la duración de las transacciones: nunca iniciar una transacción antes de tener todo listo para ejecutarla. Evitar interacción de usuario dentro de una transacción abierta.
  • Agregar índices adecuados: un Table Scan dentro de una transacción bloquea muchas más filas (o toda la tabla con lock escalation) que un Index Seek.
  • Revisar el orden de acceso a tablas: dos procesos que acceden a las mismas tablas en orden inverso generan deadlocks. Estandarizar el orden de acceso a recursos compartidos.
  • Configurar SET LOCK_TIMEOUT: para que las consultas fallen rápido en vez de esperar indefinidamente, reduciendo el impacto de los bloqueos.

Cuándo escalar el incidente a un DBA especialista

  • Deadlocks frecuentes (más de 1 por hora) afectando transacciones de negocio críticas
  • Bloqueos en cascada que paralizan decenas de sesiones y requieren kill manual repetido
  • La cadena de bloqueos tiene una sesión raíz que no se puede identificar o terminar sin riesgo
  • Los bloqueos reaparecen minutos después de resolverlos manualmente, indicando un problema estructural

Preguntas frecuentes

¿Qué diferencia hay entre un bloqueo y un deadlock?

Un bloqueo (blocking) ocurre cuando una sesión espera que otra libere un recurso. Si la sesión bloqueante termina, el bloqueo se resuelve solo y la sesión en espera continúa. Un deadlock ocurre cuando dos o más sesiones se bloquean mutuamente en ciclo: la sesión A espera que B libere un recurso, y B espera que A libere otro. SQL Server detecta estos ciclos automáticamente y selecciona una víctima (la sesión de menor costo de rollback) para terminarla y romper el ciclo.

¿Qué es RCSI y cuándo conviene habilitarlo?

Read Committed Snapshot Isolation (RCSI) hace que los lectores usen versiones de filas almacenadas en tempdb en lugar de esperar que los escritores liberen locks. Esto elimina los bloqueos lector-escritor sin modificar código de la aplicación. Conviene habilitarlo cuando los bloqueos frecuentes son entre consultas de lectura (SELECT) y escrituras concurrentes (INSERT/UPDATE/DELETE). El costo es mayor uso de tempdb para almacenar las versiones de filas.

¿Cómo identifico cuál sesión es la raíz de la cadena de bloqueos?

La sesión raíz es la que tiene blocking_session_id = 0 en sys.dm_exec_requests pero es apuntada por otras sesiones como su bloqueante. En una cadena larga (A bloquea a B, B bloquea a C), la sesión A es la raíz y es la que debe resolverse — terminar a B o C no libera a las demás.

¿El KILL de una sesión puede generar inconsistencias de datos?

No, SQL Server hace el rollback completo de la transacción abierta antes de terminar la sesión. Los datos quedan en el estado anterior al inicio de la transacción. El riesgo es el tiempo que puede tomar el rollback en transacciones largas, durante el cual la sesión aparece como rollback in progress y los recursos siguen bloqueados. Por eso es importante no hacer KILL a la ligera en sesiones con transacciones grandes en curso.