DBAtlas · Atlas de operaciones de bases de datos

Crisis de bloqueos

Síntoma

Las consultas se cuelgan, 'lock wait timeout', muchas sesiones en espera pero la CPU está baja.

1. Encuentre la cabeza de la cadena de bloqueo (root blocker)

Determine quién bloquea a quién; el verdadero culpable es la sesión que no espera nada pero hace esperar a las demás. Concéntrese en la sesión que está en la cima de la cadena.

Oracle

SELECT blocking_session, sid, serial#, username, seconds_in_wait, sql_id FROM v$session WHERE blocking_session IS NOT NULL ORDER BY seconds_in_wait DESC;

PostgreSQL

SELECT pid, usename, pg_blocking_pids(pid) blocked_by, state, query FROM pg_stat_activity WHERE cardinality(pg_blocking_pids(pid))>0;

MySQL

SELECT waiting_pid, waiting_query, blocking_pid, blocking_query FROM sys.innodb_lock_waits;

SQL Server

SELECT session_id, blocking_session_id, wait_type, wait_resource FROM sys.dm_exec_requests WHERE blocking_session_id<>0;

MongoDB

db.currentOp({ waitingForLock: true })

2. Entienda qué está haciendo el root blocker

¿Es una transacción abierta pero sin commit? ¿La aplicación la dejó 'idle in transaction'? ¿Es un batch largo? Entienda qué es antes de terminarla a ciegas: puede estar a punto de finalizar.

Oracle

SELECT s.sid, s.prev_sql_id, t.start_time, t.used_ublk FROM v$transaction t JOIN v$session s ON t.ses_addr=s.saddr;

PostgreSQL

SELECT pid, state, xact_start, now()-xact_start age, query FROM pg_stat_activity WHERE pid=<root_pid>;

3. Decida: esperar, resolver desde la aplicación o terminar

Si está a punto de finalizar, espere. Si la aplicación puede hacer commit/rollback, provóquelo. De lo contrario, si el negocio está detenido, termine el root blocker. Antes de terminarlo, considere el impacto (tiempo de rollback, datos).

4. Termine el root blocker si es necesario

Termine solo la sesión en la cabeza de la cadena; las sesiones debajo de ella se liberan automáticamente.

Oracle

ALTER SYSTEM KILL SESSION 'sid,serial#' IMMEDIATE;

PostgreSQL

SELECT pg_terminate_backend(<root_pid>);

MySQL

KILL <root_id>;

SQL Server

KILL <root_session_id>;

MongoDB

db.killOp(<opid>)

5. Corrija la causa raíz

Un índice faltante puede provocar bloqueos amplios; la aplicación puede mantener transacciones abiertas demasiado tiempo; el nivel de aislamiento puede ser incorrecto. Agregue índices, acorte las transacciones, configure un timeout para 'idle in transaction' y elija un nivel de aislamiento adecuado.

Abrir en DBAtlas →