长事务会导致mysql性能雪崩,因其持续持有锁、阻塞mvcc清理、拖慢purge线程;典型表现为trx_waiting增多或purge lag上涨;需通过performance_schema或innodb_trx识别,结合事务状态、时长及sql分析定位问题。

长事务为什么会导致 MySQL 性能雪崩
长事务本身不直接消耗 CPU,但会持续持有锁、阻止 MVCC 清理、拖慢 purge 线程,最终让整个实例响应变慢甚至卡死。最典型的信号是 SHOW ENGINE INNODB STATUS 中看到大量 TRX_WAITING 或 purge lag 持续上涨。
如何识别正在运行的长事务
MySQL 8.0+ 推荐用 performance_schema 查实时活跃事务;5.7 及更早版本依赖 information_schema.INNODB_TRX,但要注意它只显示已开启且未提交的事务,不包含空闲连接中的“假长事务”。
SELECT trx_id, trx_state, trx_started, TIMEDIFF(NOW(), trx_started) AS duration, trx_query FROM information_schema.INNODB_TRX WHERE TIME_TO_SEC(TIMEDIFF(NOW(), trx_started)) > 60;
-
trx_state = 'RUNNING'但trx_query IS NULL:可能是应用端开启了事务但没执行语句,或网络中断后连接挂起 - 结果中频繁出现相同
trx_query:大概率是业务逻辑里漏了COMMIT或异常未回滚 - 即使
duration不大,若事务内执行了大范围UPDATE或DELETE,仍可能造成锁等待链
避免长事务的实操手段
核心原则是「事务粒度与业务边界对齐」,而不是靠超时自动杀——那只是兜底,不是设计。
- 所有 DML 操作前加
SET innodb_lock_wait_timeout = 10(根据业务容忍调整),防止无限等待 - 应用层用
try/except包裹事务块,确保无论成功失败都显式调用commit()或rollback() - 禁止在事务中做 HTTP 请求、文件读写、循环 sleep 等外部耗时操作
- 批量更新拆成小事务:比如处理 10 万行,用
WHERE id BETWEEN ? AND ?分页,每 1000 行提交一次 - 读多写少场景优先用
SELECT ... LOCK IN SHARE MODE替代SELECT FOR UPDATE,降低锁强度
监控与告警必须覆盖的关键指标
光看 Threads_running 或 QPS 发现不了长事务问题。真正有效的指标藏在 InnoDB 内部:
-
Innodb_trx_rseg_history_len:历史列表长度,持续 > 10000 是 purge 延迟明显信号 -
innodb_max_purge_lag配置值是否被频繁触发(查SHOW STATUS LIKE 'Innodb_max_purge_lag%) - 每分钟扫描
INNODB_TRX表,统计平均trx_duration并告警 > 30s 的实例 - 慢日志中出现
Rows_examined极高但执行时间短的事务:说明它在等锁,而非真慢
事务不是越长越“稳”,而是越长越危险。最容易被忽略的是连接池配置——maxIdleTime 设为 0 或极大值,会让空闲事务连接长期不释放,伪装成长事务。











