information_schema.innodb_trx 看不到等待锁的事务,因该视图仅显示活跃且已持有锁的事务;真正阻塞业务的是未出现在其中的等待者,需通过 performance_schema.data_lock_waits 等表联合分析。

为什么 INFORMATION_SCHEMA.INNODB_TRX 看不到正在等锁的事务?
因为这个视图只显示「活跃且已持有锁」的事务,不包含「被阻塞、正在等待锁」的事务。真正卡住业务的往往就是那些没出现在这里的等待者。
要抓到它们,必须联合查 INFORMATION_SCHEMA.INNODB_LOCK_WAITS 和 INFORMATION_SCHEMA.INNODB_LOCKS(MySQL 8.0.24+ 已弃用后者,改用 performance_schema.data_locks)——但注意:INNODB_LOCK_WAITS 在 MySQL 8.0.24 后也已被移除,替代方案是直接查 performance_schema.data_lock_waits。
- MySQL 8.0.24 及以后:只用
performance_schema.data_lock_waits+performance_schema.data_locks+performance_schema.threads - MySQL 8.0.0–8.0.23:仍可用
INNODB_LOCK_WAITS,但需确保innodb_status_output_locks=ON且 performance_schema 开启 - 默认情况下
performance_schema的 data_lock 相关 instruments 是关闭的,必须手动启用:UPDATE performance_schema.setup_instruments SET ENABLED = 'YES', TIMED = 'YES' WHERE NAME LIKE 'wait/lock%';
怎么写一条能定位「热点行」的查询?
目标不是列出所有锁,而是快速识别被多个事务反复争抢的同一行记录(比如订单表里 order_id = 10086 被 12 个事务排队等着更新)。
核心思路:从 performance_schema.data_lock_waits 找出等待关系,关联 data_locks 提取被锁的资源(如 TABLE: `db`.`t_order` , INDEX: `PRIMARY` , SPACE: 123 , PAGE: 456 , RECORD: 7),再按 OBJECT_SCHEMA、OBJECT_NAME、INDEX_NAME 和关键字段值反查具体行。
MySQL 9.6.0是面向Linux平台的2026年创新版本,核心架构迎来重大革新。其将外键约束与级联操作从InnoDB引擎层上移至SQL层,确保所有数据变更均被完整记录至Binlog,彻底解决了CDC(变更数据捕获)与主从复制中的数据不一致难题。此外,该版本引入container_aware启动选项以原生适配容器环境,并对审计日志进行了组件化重构,为追求极致数据一致性与云原生体验的开发者提供了全新选择。
- 先确认锁等待聚合:
SELECT blocking_trx_id, COUNT(*) AS waiters FROM performance_schema.data_lock_waits GROUP BY blocking_trx_id ORDER BY waiters DESC LIMIT 5;
- 再查该阻塞事务锁住的具体行(需结合
data_locks中的LOCK_DATA字段,它可能是 JSON 格式,例如"10086"或"10086, 2") -
LOCK_DATA不一定可直接用于 SQL 查询——它只是 InnoDB 层面的内部标识,对主键是值本身,对二级索引可能含索引列+主键,得根据INDEX_NAME和表结构推断
LOCK_DATA 显示 "10086",但 SELECT * FROM t_order WHERE id = 10086 很快,为什么还堵?
因为行锁冲突未必发生在查询上,而常发生在 UPDATE 或 DELETE 的写路径中,尤其当事务未提交、持有 S/X 锁时间过长时。
更隐蔽的情况:该行被一个长事务(比如未提交的 START TRANSACTION; UPDATE ...;)锁住,后续所有修改同一行的语句都会卡在 data_lock_waits 里,但读操作(SELECT)在 RR 隔离下走 MVCC,不感知锁,所以不慢——用户感知的“卡”其实是写请求超时或连接堆积。
- 检查阻塞事务的
TRX_STATE和TRX_STARTED时间(通过performance_schema.threads关联PROCESSLIST_ID查原始 SQL) - 关注
TRX_WAITING = 0且TRX_STATE = 'RUNNING'但TRX_STARTED是 5 分钟前的事务——极大概率是漏了COMMIT -
LOCK_MODE为X表示排他锁,S是共享锁;但 UPDATE 普遍升级为 X 锁,即使只改一个字段
为什么开了 performance_schema 还查不到 data_locks 数据?
不是开关没开,而是默认禁用了底层采集器。仅设置 performance_schema = ON 不够,必须显式启用 lock 相关 instruments 和 consumers。
- 启用采集器:
UPDATE performance_schema.setup_instruments SET ENABLED = 'YES' WHERE NAME IN ('wait/lock/innoDB/autoinc', 'wait/lock/innoDB/buffer_pool', 'wait/lock/innoDB/table', 'wait/lock/innoDB/record'); - 启用消费者:
UPDATE performance_schema.setup_consumers SET ENABLED = 'YES' WHERE NAME LIKE 'events%lock%';
- 重启后生效,且只对新建立的连接有效;已有连接的锁行为不会被追溯
- 高频写入场景下开启 lock 监控有约 3%~5% 性能损耗,建议仅在排查期开启,定位完及时关掉
真正难的不是查到哪一行被争抢,而是判断为什么这一行成了瓶颈——是业务逻辑强制串行更新(比如余额扣减强一致性)、还是索引缺失导致锁范围扩大(本来该锁一行,结果锁了一整个页)。这些没法靠视图直接回答,得回到代码和执行计划里看。










