data_lock_waits比innodb_lock_waits更可靠,因后者在mysql 8.0+已被移除,而前者记录实时锁等待关系,需关联innodb_trx获取sql,并确保performance_schema相关consumers和instruments已启用。

不能只看 SHOW ENGINE INNODB STATUS —— 它只留“最后一具尸体”,而 performance_schema 才能抓到正在掐脖子的现场。
为什么 data_lock_waits 比 INNODB_LOCK_WAITS 更可靠?
MySQL 8.0+ 已彻底移除 INNODB_LOCK_WAITS 表,继续查它会报错 Table 'information_schema.INNODB_LOCK_WAITS' doesn't exist。新机制依赖 performance_schema.data_lock_waits,它记录的是实时锁等待关系,不是快照。
-
data_lock_waits中的BLOCKING_ENGINE_TRANSACTION_ID和REQUESTING_ENGINE_TRANSACTION_ID是十六进制字符串(如1402356789012345),需与INNODB_TRX.trx_id精确匹配(注意:后者是十进制整数,但实际值相同) - 该表不包含 SQL 内容,必须关联
INNODB_TRX才能拿到trx_query - 若查询为空,不代表没锁等待——可能锁已释放,或
setup_consumers未启用events_waits_current
必须启用的 instruments 和 consumers
默认情况下,performance_schema 不采集锁事件。不配就查不到任何数据。
- 检查消费者是否开启:
SELECT * FROM performance_schema.setup_consumers WHERE NAME LIKE 'events_waits%';—— 确保events_waits_current和events_waits_history_long的ENABLED列为YES - 启用锁仪器:
UPDATE performance_schema.setup_instruments SET ENABLED = 'YES', TIMED = 'YES' WHERE NAME LIKE 'wait/lock%'; - 该操作立即生效,无需重启;但若实例启用了
performance_schema=OFF启动参数,则必须重启
怎么把 waiting_trx 和 blocking_trx 对上真实 SQL?
只查 data_lock_waits 得到两个事务 ID,但不知道它们在跑什么。必须用 INNODB_TRX 关联出具体语句,否则无法定位业务代码。
- 典型关联写法:
SELECT r.trx_id AS waiting_trx, r.trx_query AS waiting_sql, b.trx_id AS blocking_trx, b.trx_query AS blocking_sql FROM performance_schema.data_lock_waits w JOIN information_schema.INNODB_TRX r ON w.REQUESTING_ENGINE_TRANSACTION_ID = r.trx_id JOIN information_schema.INNODB_TRX b ON w.BLOCKING_ENGINE_TRANSACTION_ID = b.trx_id; - 注意:如果某事务已提交或回滚,
INNODB_TRX中查不到,对应字段会 NULL —— 这说明等待已解除,但阻塞源可能刚消失 - 优先看
r.trx_state = 'LOCK WAIT'的行,这是正在卡住的事务;b.trx_state通常为RUNNING或LOCK WAIT(若它也在等别人)
容易被忽略的权限和过滤陷阱
即使配置全开,普通账号也可能查不到完整信息。
- 查
INNODB_TRX和PROCESSLIST需要PROCESS权限;查performance_schema表需要SELECT权限,但部分表(如data_locks)还要求ROLE_REPLICATION_ADMIN或SYSTEM_VARIABLES_ADMIN(取决于 MySQL 版本) - 别用
SELECT * FROM performance_schema.data_locks—— 数据量大时会拖慢查询;加LIMIT 100,或按ENGINE_TRANSACTION_ID过滤特定事务 - 线上高并发场景下,
data_lock_waits可能瞬时存在又消失;建议配合pt-deadlock-logger或定时轮询脚本捕获
真正难的不是查到谁在等谁,而是确认那个 blocking_trx 为什么迟迟不释放锁——它可能正在执行一个没索引的 UPDATE、正卡在磁盘 I/O、或应用层根本没 commit。这时候得顺着 trx_mysql_thread_id 去 PROCESSLIST 看 INFO 和 TIME 字段,再结合应用日志交叉验证。











