MySQL 8.0+必须用performance_schema.data_lock_waits和data_locks,因INNODB_LOCK_WAITS已彻底移除且依赖的INNODB_LOCKS表被废弃,查询返回空集或报错,并非权限问题,而是表本身不存在。

直接看 performance_schema.data_lock_waits 和 data_locks,MySQL 8.0+ 必须用这套,INNODB_LOCK_WAITS 已失效且查不到真实阻塞链。
为什么不能继续用 INNODB_LOCK_WAITS 查锁等待
MySQL 8.0 彻底移除了 INNODB_LOCKS 表,而 INNODB_LOCK_WAITS 依赖它做关联。即使你执行 SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS,返回结果也为空或报错——这不是权限问题,是表本身已被废弃。
常见错误现象:
- 查询
INNODB_LOCK_WAITS返回空集,但实际有事务卡在LOCK WAIT状态 - 用
INNODB_TRX能看到trx_state = 'LOCK WAIT',却找不到对应 blocking_trx_id - 误以为没锁竞争,结果业务持续超时,
Lock wait timeout exceeded频发
根本原因:8.0 改用 performance_schema 统一管理锁元数据,所有锁对象、等待关系、持有者线程都映射到 data_locks 和 data_lock_waits,字段更明确,且带 OWNER_THREAD_ID 可直连 processlist。
performance_schema.data_lock_waits 怎么查出谁等谁
先确认采集器已启用:
SELECT VARIABLE_VALUE FROM performance_schema.setup_consumers WHERE NAME = 'global_instrumentation';
若返回 NO,需手动开启:
UPDATE performance_schema.setup_consumers SET ENABLED = 'YES' WHERE NAME = 'global_instrumentation';
然后执行核心查询(带库表过滤,避免干扰):
SELECT r.OBJECT_SCHEMA, r.OBJECT_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 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' AND r.OBJECT_NAME = 'your_table';
关键点:
-
waiting_thread和blocking_thread是线程 ID,可直接去SHOW PROCESSLIST或information_schema.processlist查 SQL 和状态 -
requested_mode为X且blocking_mode也是X,说明是行锁互斥;若一方是S,可能是 MVCC 版本读被写阻塞 - 该视图只反映“当前瞬时等待”,不是历史累计,需配合
innodb_row_lock_current_waits判断是否高频发生
data_locks 里怎么看锁在哪一行、什么模式
data_locks 是锁的“快照源”,每条记录代表一个锁实例。重点关注:
-
OBJECT_SCHEMA+OBJECT_NAME:锁定的库表 -
LOCK_MODE:常见值为S(共享)、X(排他)、IS/IX(意向锁) -
LOCK_TYPE:通常是RECORD(行锁)或TABLE(表锁) -
INDEX_NAME:行锁落在哪个索引上,PRIMARY表示主键,GEN_CLUST_INDEX是隐式聚簇索引 -
LOCK_DATA:行锁的具体值,如3表示主键等于 3 的那行;如果是范围锁,会显示最小/最大值区间(如5, 10)
示例:某条记录 LOCK_TYPE = 'RECORD'、INDEX_NAME = 'PRIMARY'、LOCK_DATA = '7',说明事务正持有一个对主键值为 7 的行的 X 锁——这就是最典型的阻塞源头。
结合 innodb_row_lock_* 状态变量快速初筛
不查表、不依赖权限,普通账号也能跑的轻量检查:
SHOW STATUS LIKE 'innodb_row_lock_%';
重点关注三项:
-
Innodb_row_lock_current_waits:大于 0 就说明此刻有事务在等行锁,立刻进data_lock_waits查细节 -
Innodb_row_lock_time_avg:单位毫秒,从0.2突升到40+,基本可断定有长事务或未提交事务拖慢了锁释放 -
Innodb_row_lock_waits:累计等待次数,适合看趋势(比如 Grafana 监控),单次查看意义不大
注意:SHOW OPEN TABLES WHERE In_use > 0 只反映元数据锁(MDL)或表级锁,对 InnoDB 行锁完全无感,别指望靠它定位 UPDATE 卡住的问题。
真正难的不是查到谁在等、谁在挡,而是判断那个 blocking_thread 为什么迟迟不释放锁——它可能是个没 COMMIT 的交互式事务,也可能在执行一个耗时 20 秒的子查询,还可能卡在应用层网络 IO 上。这时候必须把 OWNER_THREAD_ID 和 processlist 的 Time、State、Info 三列一起看,才能分清是数据库问题还是上游调用方的问题。











