DBAtlas · 数据库运维图谱

长时间运行 / 未结束的事务

长时间运行或未结束的事务正在累积锁、undo 和膨胀(bloat)。我们找出问题事务,确定其类型(idle in transaction、长批处理、影响),并安全地解决它。

最早的未结束事务是哪一个?

按开始时间列出未结束的事务。最早的那个通常就是问题的根源。检查其状态:是正在活跃运行,还是处于等待提交的 'idle in transaction' 状态?

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(忘记提交,处于空闲)
  • 活跃但运行时间极长的批处理/DML
  • 事务持续期间正在累积锁/膨胀/undo

为什么会出现 idle in transaction?

会话打开了事务,但处于空闲状态,没有运行查询;也就是说,忘记了 commit/rollback。这会不必要地占用锁和 undo。是修复应用就足够,还是需要紧急终止它?

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;
  • 应用/连接池没有提交(永久修复)
  • 我需要立即终止它

活跃的长事务在做什么?

该会话确实在运行(active)。它是单个巨型 DML/报表,还是一个正在让其他会话等待、必须紧急切断的阻塞者?

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;
  • 单个巨型 DML/报表;需要拆分
  • 它正在让其他会话等待;紧急终止

长事务正在累积什么?

确定长事务的副作用:主要是导致其他会话等待的锁积压,还是因持有旧的行版本而阻碍清理(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;
  • 锁积压正在让其他会话等待
  • 旧版本堆积正在阻碍清理(undo/膨胀)

根本原因:应用没有提交(idle in transaction)

连接池或应用打开事务后,不提交/回滚就让连接保持空闲。这会不必要地占用锁和 undo。

解决方案:安全地终止问题会话

如果一个阻塞/长时间运行的会话正在让其他会话等待,必须以受控方式终止它。终止会触发回滚,可能需要空间/时间;需谨慎。

根本原因:单个巨型 DML/报表

在单个事务中处理数百万行的 DML,或运行时间极长的报表,会在整个持续期间累积锁和 undo/膨胀。

根本原因:锁积压队列

由于持有的锁,长事务在其身后形成了等待队列;许多会话正在等待同一资源。

根本原因:旧版本堆积(undo/膨胀)

长时间运行的事务阻止了对其之前的旧行版本的清理。在 Postgres 中表现为表/索引膨胀,在 Oracle 中表现为 undo 压力。

在 DBAtlas 中打开 →