长事务是什么
长时间不提交的事务会拖住整个存储引擎的清理工作:InnoDB 的 purge 无法回收旧版本,历史链表与回滚段持续增长;PostgreSQL 的 vacuum 无法回收死元组,表与索引一起膨胀。长事务还容易与 DDL 相互阻塞,把锁等待传导给线上请求。
基本信息
| InnoDB 影响 | 阻止 purge 回收旧版本,回滚段与历史链表膨胀 |
|---|---|
| PostgreSQL 影响 | 阻止 vacuum 回收死元组,表与索引膨胀 |
| 常见来源 | 连接池里开了事务忘了提交,形成 idle in transaction |
| 排查 MySQL | information_schema.INNODB_TRX 按 trx_started 排序 |
| 排查 PG | pg_stat_activity 里 xact_start 非空、状态为 idle in transaction |
| 护栏 | PG 可设 idle_in_transaction_session_timeout;应用层必须保证提交或回滚 |
MySQL 排查
MySQL 排查
SELECT trx_id, trx_state, trx_started, trx_mysql_thread_id, trx_query
FROM information_schema.INNODB_TRX
ORDER BY trx_started; -- 最上面一行就是活得最久的事务
SELECT id, user, db, command, time, state, info
FROM information_schema.PROCESSLIST
WHERE time > 60
ORDER BY time DESC; -- 看具体连接在做什么PostgreSQL 排查
PostgreSQL 排查
SELECT pid, state, xact_start,
now() - xact_start AS age,
state_change,
query
FROM pg_stat_activity
WHERE xact_start IS NOT NULL
ORDER BY xact_start; -- 重点看 state = 'idle in transaction' 的行危害与对照
| 维度 | MySQL 8(InnoDB) | PostgreSQL |
|---|---|---|
| 清理机制 | purge 回收旧版本 | vacuum 回收死元组 |
| 受影响对象 | 回滚段与历史链表膨胀 | 表与索引膨胀 |
| 排查视图 | information_schema.INNODB_TRX | pg_stat_activity |
| 常见元凶 | 连接池里未提交的事务 | idle in transaction 会话 |
| 护栏手段 | 靠应用层与连接池管理 | idle_in_transaction_session_timeout |
典型使用场景
- 排查库变慢:先看有没有长事务挂着
- 连接池治理:找出开了事务却不提交的连接
- 上线前检查:确认待执行的 DDL 不会被长事务挡住
- 批量作业调优:把大事务拆成小批次
- 数据同步任务:避免在事务里调用外部接口
- 容量告警排查:表膨胀时先排除长事务因素
长事务不一定正在跑语句:idle in transaction 表示事务已经开启但当前没有 SQL 执行,它同样阻止清理。排查时状态列比耗时列更值得关注。
在事务里做网络调用是典型隐患:接口超时或重试会把事务拖到几十秒以上,锁与清理都被牵连。外部调用应放在事务之外,数据准备完再开启事务写库。