Transacción de larga duración / abierta
Una transacción de larga duración o abierta está acumulando bloqueos, undo y bloat. Localizamos la transacción causante, determinamos su tipo (idle in transaction, lote largo, impacto) y la resolvemos de forma segura.
¿Cuál es la transacción abierta más antigua?
Liste las transacciones abiertas por hora de inicio. La más antigua suele ser el origen del problema. Compruebe su estado: ¿se está ejecutando activamente o está 'idle in transaction' esperando un commit?
SELECT s.sid, s.serial#, s.username, s.status, t.start_time, t.used_ublk*8/1024 AS undo_mb
FROM v$transaction t JOIN v$session s ON s.taddr=t.addr
ORDER BY t.start_time;- idle in transaction (commit olvidado, inactiva)
- Lote/DML activo pero de muy larga duración
- Acumula bloqueos/bloat/undo mientras la transacción continúa
¿Por qué se produce idle in transaction?
La sesión abrió una transacción pero permanece inactiva sin ejecutar ninguna consulta; es decir, se olvidó el commit/rollback. Esto retiene bloqueos y undo innecesariamente. ¿Basta con una corrección en la aplicación, o hay que terminarla con urgencia?
SELECT pid, now()-state_change AS idle_age, left(query,80) AS last_query
FROM pg_stat_activity WHERE state='idle in transaction' ORDER BY state_change;- La aplicación/el pool de conexiones no hace commit (solución permanente)
- Necesito terminarla ahora mismo
¿Qué está haciendo la transacción larga activa?
La sesión se está ejecutando realmente (activa). ¿Es un único DML/informe enorme, o un bloqueador que hace esperar a otras sesiones y debe cortarse con urgencia?
SELECT s.sid, s.serial#, sq.sql_text, s.last_call_et AS running_secs
FROM v$session s JOIN v$sql sq ON sq.sql_id=s.sql_id
WHERE s.status='ACTIVE' AND s.type='USER' ORDER BY s.last_call_et DESC;- Un único DML/informe enorme; hay que dividirlo
- Hace esperar a otros; terminarla con urgencia
¿Qué está acumulando la transacción larga?
Determine el efecto secundario de la transacción larga: ¿se trata sobre todo de una acumulación de bloqueos que hace esperar a otras sesiones, o de bloat por retener versiones antiguas de filas y bloquear la limpieza (VACUUM/undo)?
SELECT pid, pg_blocking_pids(pid) AS blocked_by FROM pg_stat_activity WHERE cardinality(pg_blocking_pids(pid))>0;
SELECT max(age(backend_xmin)) AS max_xmin_age FROM pg_stat_activity WHERE backend_xmin IS NOT NULL;- Una acumulación de bloqueos hace esperar a otras sesiones
- La acumulación de versiones antiguas bloquea la limpieza (undo/bloat)
Causa raíz: la aplicación no hace commit (idle in transaction)
El pool de conexiones o la aplicación abre una transacción y luego mantiene la conexión inactiva sin hacer commit/rollback. Esto retiene bloqueos y undo innecesariamente.
Solución: terminar de forma segura la sesión causante
Si una sesión bloqueadora/larga hace esperar a otras, debe terminarse de forma controlada. La terminación desencadena un rollback, que puede necesitar espacio/tiempo; tenga cuidado.
Causa raíz: un único DML/informe enorme
Un DML que procesa millones de filas en una sola transacción, o un informe muy largo, acumula bloqueos y undo/bloat durante toda su duración.
Causa raíz: cola de bloqueos acumulados
Por los bloqueos que retiene, la transacción larga ha creado una cola de espera detrás de ella; muchas sesiones esperan el mismo recurso.
Causa raíz: acumulación de versiones antiguas (undo/bloat)
La transacción de larga duración impide la limpieza de las versiones antiguas de filas anteriores a ella. En Postgres se manifiesta como bloat de tablas/índices; en Oracle, como presión de undo.