innodb_trx查不到源头sql是因为innodb不记录事务内最后执行的语句,trx_query字段常为空;真正可用的是performance_schema.events_statements_current表,需join processlist和threads定位sleep连接的最近sql。

为什么INNODB_TRX查不到源头SQL
直接查 information_schema.INNODB_TRX 只能看到事务 ID、开始时间、状态、线程 ID 和隔离级别,但 INFO 字段永远为空——InnoDB 本身不记录事务内最后执行的语句。这不是配置问题,是存储引擎设计决定的:事务上下文和 SQL 文本不在同一层维护。
常见误区是以为 trx_state = 'RUNNING' 就一定有活跃 SQL 在跑;实际上大量问题来自 COMMAND = 'Sleep' 的悬挂连接,它 BEGIN 之后什么都没做,却一直占着锁和 Undo 空间。
用 events_statements_current 关联线程找最近 SQL
MySQL 5.7 的 performance_schema.events_statements_current 表会保留每个线程最后一次成功执行的语句(不是事务内所有语句,而是最新一条),只要 performance_schema 已启用且采集器打开,就能反向定位。
- 先确认开关已开:
SELECT @@performance_schema;必须返回1;再执行UPDATE performance_schema.setup_consumers SET ENABLED = 'YES' WHERE NAME = 'events_statements_current'; - 关联查询时必须三表 JOIN:
PROCESSLIST找 Sleep 连接 →threads转换为 thread_id →events_statements_current拿sql_text - 典型语句:
SELECT p.ID, p.USER, p.HOST, p.DB, p.TIME, t.THREAD_ID, e.SQL_TEXT FROM information_schema.PROCESSLIST p JOIN performance_schema.threads t ON p.ID = t.PROCESSLIST_ID JOIN performance_schema.events_statements_current e ON t.THREAD_ID = e.THREAD_ID WHERE p.COMMAND = 'Sleep' AND p.TIME > 300 AND e.SQL_TEXT IS NOT NULL;
为什么 sys.session 在 5.7 中不可靠
sys.session 是 MySQL 5.7.9+ 引入的视图,但它底层依赖 events_statements_history_long,而该表默认关闭、且内存消耗大,线上通常不会启用。即使开了,它的 current_statement 字段也常为 NULL——因为线程处于 Sleep 状态时,performance_schema 不会主动刷新语句缓存。
所以别依赖 SELECT * FROM sys.session WHERE CONN_ID = ?,它在绝大多数生产环境里返回空或过期内容。真正能用的只有显式 JOIN events_statements_current 的方式。
通用日志不是备选方案,而是兜底手段
开启 general_log 能看到所有到达 MySQL 的语句,包括未提交事务里的每一条,但它代价极高:IO 暴涨、磁盘写满风险、影响性能。只应在确认问题复现路径后、短时开启(比如 2 分钟),并配合 general_log_file 定位到具体连接 ID。
- 启用:
SET GLOBAL general_log = 1;,然后立刻查SHOW VARIABLES LIKE 'general_log_file'; - 查日志时按连接 ID 过滤,例如搜索
# Time:.*20040(其中 20040 是 PROCESSLIST 中看到的ID) - 关掉:
SET GLOBAL general_log = 0;,避免持续写入
真正难的不是找到那条 SQL,而是判断它是否还在生效——同一个连接 ID 可能已重连,日志里看到的可能是上一轮会话的残留。务必结合 TRX_STARTED 时间戳交叉验证。











