直接查 information_schema.innodb_trx 最可靠,因其强制记录所有未提交事务的 trx_started 时间,不受线程 sleep 状态干扰;而 show processlist 易误判,因长事务常显示为空闲连接且 info 为空。

直接查 information_schema.INNODB_TRX 是最可靠的方式,比 SHOW PROCESSLIST 更准——因为未提交事务常处于 Sleep 状态且 Info 为空,INNODB_TRX 却强制记录所有活跃事务的起始时间,不会漏掉“安静的幽灵”。
为什么 SHOW PROCESSLIST 容易误判长事务
一个显式开启的事务(BEGIN 或 SET autocommit = 0)执行完 SQL 后若没 COMMIT 或 ROLLBACK,线程状态通常变成 Sleep,Info 字段为空。这时候它在 SHOW PROCESSLIST 里就像个空闲连接,仅靠 Time 列判断容易出错:比如 Time = 320,你以为是连接空闲了 5 分多钟,其实事务已持锁运行 320 秒。
INNODB_TRX 的 trx_started 是真实起点,不受线程状态干扰。只要事务没结束,它就一定在表里。
-
trx_state = 'ACTIVE'才代表事务仍在生命周期内;RUNNING、LOCK WAIT都是子状态,但都属于活跃 -
trx_query为空 ≠ 没操作,大概率是语句已执行完但没提交;若非空,则卡在某条 SQL 上(可能是慢查询或锁等待) -
trx_mysql_thread_id是 kill 的目标 ID,不是trx_id;后者是 InnoDB 内部事务 ID,不能用于KILL
怎么快速定位长事务源头(用户 + 主机 + 命令)
单靠 INNODB_TRX 只能看到线程 ID 和起始时间,不知道是谁、从哪连进来的。必须关联 information_schema.PROCESSLIST:
- 用
trx_mysql_thread_id关联PROCESSLIST.ID,拿到USER、HOST、DB、COMMAND和INFO - 如果
PROCESSLIST.COMMAND = 'Sleep'且trx_state = 'ACTIVE',基本可断定是应用端忘了提交 -
PROCESSLIST.TIME是线程空闲秒数,不是事务存活时间;交叉比对trx_started才能确认是否异常
推荐组合查询:
SELECT t.trx_id, t.trx_started, TIMESTAMPDIFF(SECOND, t.trx_started, NOW()) AS run_sec, t.trx_state, p.USER, p.HOST, p.DB, p.COMMAND, p.INFO FROM information_schema.INNODB_TRX t JOIN information_schema.PROCESSLIST p ON t.trx_mysql_thread_id = p.ID WHERE t.trx_state = 'ACTIVE' AND TIMESTAMPDIFF(SECOND, t.trx_started, NOW()) > 120;
为什么别依赖 trx_query 找慢 SQL
trx_query 只显示事务中“最后一条执行的 SQL”,不是“最重一句”,更不是慢查询线索:
- 为空时,只说明事务开了但还没发任何语句,或刚执行完就挂起;和索引无关
- 被截断(默认最多 1024 字节)是视图定义限制,跟执行计划完全无关
- 真正影响性能的是锁等待、大修改量(
trx_rows_modified)、或持有大量锁(trx_lock_structs),这些字段才该重点关注
要定位慢 SQL,得用 performance_schema.events_statements_history 或开启慢日志,而不是盯着 INNODB_TRX 的 trx_query。
监控频率与性能损耗的平衡点
频繁查 INNODB_TRX 本身会争抢 trx_sys->mutex,高并发下引发 CPU 尖刺:
- 每次查询都要遍历所有活跃事务内存结构,并做字段拷贝和权限校验;当
trx_rows_modified或trx_lock_structs极大时,成本线性上升 - 生产环境轮询间隔建议 ≥ 10 秒;若需更实时感知,优先启用
performance_schema.events_transactions_current(需手动开启相关 consumer) - 永远不要
SELECT *,只取真正需要的字段,例如trx_id,trx_state,trx_started,trx_mysql_thread_id,trx_rows_modified - 加
WHERE过滤,比如WHERE trx_started ,跳过短事务遍历
最隐蔽的风险往往不在事务本身,而在你查它的姿势——查得越勤、越宽泛,越可能把自己变成压垮数据库的最后一根稻草。











