MySQL 8.0 中 INNODB_LOCKS 和 INNODB_LOCK_WAITS 表已被彻底移除,查不到锁等待细节是因表物理删除而非权限或语法问题;必须启用 performance_schema 的 wait/lock 相关 instruments 后,通过 data_locks 与 data_lock_waits 关联查询锁等待关系。

MySQL 8.0 中 INNODB_LOCKS 和 INNODB_LOCK_WAITS 表已彻底移除,查不到锁等待细节不是权限或语法问题,是表本身不存在——必须转向 performance_schema.data_locks 和 performance_schema.data_lock_waits。
为什么直接查 INNODB_LOCK_WAITS 返回空?
这不是你漏了 WHERE 条件,也不是账号没权限。MySQL 官方从 8.0.1 起正式删除了 INFORMATION_SCHEMA.INNODB_LOCKS 表,而 INNODB_LOCK_WAITS 依赖它做 JOIN,所以查询返回空集或报错 Table 'information_schema.INNODB_LOCK_WAITS' doesn't exist 是必然结果。
- 即使你看到老教程里有
blocking_trx_id字段,那也只适用于 MySQL 5.7 及更早版本 -
SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX WHERE trx_state = 'LOCK WAIT'可能仍能查到等待事务,但你无法通过blocking_trx_id回溯阻塞者——因为关联表没了 - 别试
SHOW ENGINE INNODB STATUS\G里的TRANSACTIONS区块找等待关系:它只显示事务摘要,不提供可关联的锁 ID 或线程映射
怎么用 data_lock_waits 查出“谁在等谁”?
核心逻辑是:等待关系存在于 data_lock_waits,锁对象细节在 data_locks,两者靠 ENGINE_LOCK_ID 关联。但前提是采集器必须启用。
- 先确认采集开关已开:
SELECT VARIABLE_VALUE FROM performance_schema.setup_consumers WHERE NAME = 'global_instrumentation';结果必须为YES;若为NO,执行UPDATE performance_schema.setup_consumers SET ENABLED = 'YES' WHERE NAME = 'global_instrumentation'; - 再检查锁相关 instruments:
SELECT ENABLED FROM performance_schema.setup_instruments WHERE NAME LIKE '%wait/lock%';至少要有wait/lock/metadata/sql/mdl和wait/lock/innoDB两行是YES - 执行标准关联查询(带库过滤防干扰):
SELECT r.OBJECT_SCHEMA, r.OBJECT_NAME, r.INDEX_NAME, r.LOCK_MODE AS requested_mode, b.LOCK_MODE AS blocking_mode, r.OWNER_THREAD_ID AS waiting_thread, b.OWNER_THREAD_ID AS blocking_thread, r.LOCK_DATA AS requested_data, b.LOCK_DATA AS blocking_data FROM performance_schema.data_lock_waits w JOIN performance_schema.data_locks r ON w.REQUESTING_ENGINE_LOCK_ID = r.ENGINE_LOCK_ID JOIN performance_schema.data_locks b ON w.BLOCKING_ENGINE_LOCK_ID = b.ENGINE_LOCK_ID WHERE r.OBJECT_SCHEMA = 'your_db';
data_locks 的 LOCK_DATA 字段到底显示什么?
这个字段是定位具体哪一行被锁住的关键,但它不是总显示主键值——取决于加锁时走的是哪个索引。
- 如果 SQL 走主键索引(如
WHERE id = 100),LOCK_DATA显示的就是主键值,例如100 - 如果走二级索引(如
WHERE status = 'pending'),LOCK_DATA显示的是该二级索引字段值 + 对应主键值,例如'pending', 100 - 如果是间隙锁(
LOCK_MODE含GAP)或临键锁(NEXT-KEY),LOCK_DATA可能为空,或显示区间边界,比如100表示锁住了 (50,100] 这个范围 - 注意:
LOCK_STATUS = 'WAITING'表示该锁请求尚未获得,此时LOCK_DATA仍有效,代表它想锁的目标
如何把锁等待线程和 PROCESSLIST 对上号?
data_locks.OWNER_THREAD_ID 就是你要找的线程 ID,它和 information_schema.PROCESSLIST.ID、SHOW PROCESSLIST 第一列完全一致——不是近似,是同一数值。
- 拿到
blocking_thread = 12345后,直接执行SELECT * FROM information_schema.PROCESSLIST WHERE ID = 12345\G;,就能看到它当前的State(比如Updating)、Time(已运行秒数)、Info(正在执行的 SQL) - 如果
State是Locked或Waiting for table metadata lock,说明不是 InnoDB 行锁问题,而是元数据锁(MDL)卡住,得去查performance_schema.metadata_locks - 别依赖
trx_mysql_thread_id:它在INNODB_TRX里虽存在,但 8.0+ 中与OWNER_THREAD_ID并不总一致,尤其在预编译语句或连接池复用场景下,以OWNER_THREAD_ID为准
真正容易被忽略的是采集开关的默认状态:虽然多数 MySQL 8.0 发行版默认开启 global_instrumentation,但 wait/lock/innoDB instruments 默认是 NO。不手动打开它,data_locks 里只会看到表锁、MDL 锁,看不到任何 InnoDB 行级锁细节——连 LOCK_TYPE = 'RECORD' 都不会出现。


















