能直接用performance_schema.data_lock_waits查到谁在等谁,但需mysql≥5.7、启用wait/lock/innodb instrument及%locks% consumers;须关联data_locks获取表名、索引、lock_data等关键信息,并通过threads和events_statements_history定位阻塞sql。

能直接用 performance_schema.data_lock_waits 查到谁在等谁,但前提是 MySQL ≥ 5.7、锁采集 instrument 已开启、consumers 也已启用——否则查出来永远是空的,不是 SQL 写错了,是开关根本没开。
确认 wait/lock/innoDB instrument 是否真正启用
很多人卡在这一步:表存在、SQL 能执行、结果却为空。根本原因不是权限或语法问题,而是相关 instrument 默认关闭。
- 运行
SELECT * FROM performance_schema.setup_instruments WHERE NAME LIKE 'wait/lock/innoDB%';,检查ENABLED和Timed列是否都为YES - 若为
NO,MySQL 5.7–8.0 必须静态配置:performance_schema_instrument = 'wait/lock/innoDB%=ON'加入my.cnf,然后重启mysqld - MySQL 8.0+ 虽支持部分动态开启,但
wait/lock/innoDB/row_lock必须静态配置才稳定生效
必须同时启用 locks 相关 consumers
data_lock_waits 和 data_locks 的数据不会自动写入,除非对应 consumer 开启。
- 执行
UPDATE performance_schema.setup_consumers SET ENABLED = 'YES' WHERE NAME LIKE '%locks%'; - 关键 consumer 包括:
events_statements_current(用于关联阻塞 SQL)、global_instrumentation(影响锁事件采集) - 改完不重启,但需确保后续新连接能采集;已有连接可能仍无锁事件,建议观察新事务
查实时锁等待链:data_lock_waits 必须连 data_locks
data_lock_waits 只存 ID 关系,不带表名、索引名、LOCK_DATA ——单查它等于白查。
- 标准关联写法:
SELECT w.OBJECT_SCHEMA, w.OBJECT_NAME, w.INDEX_NAME, w.LOCK_TYPE, w.LOCK_MODE, w.LOCK_STATUS, w.BLOCKING_ENGINE_TRANSACTION_ID, w.REQUESTING_ENGINE_TRANSACTION_ID, d.LOCK_DATA FROM performance_schema.data_lock_waits w JOIN performance_schema.data_locks d ON w.REQUESTING_ENGINE_LOCK_ID = d.ENGINE_LOCK_ID; -
LOCK_MODE值要会读:S是共享锁,X是排他锁,NEXT_KEY表示临键锁(记录 + 间隙),GAP表示纯间隙锁 -
LOCK_DATA是关键:显示具体主键值(如12345)或范围(如10, 20),直接暴露热点行或争用间隙
定位持锁者正在执行的 SQL
知道谁在等还不够,得知道阻塞方到底卡在哪条语句上——它可能是个未提交事务,也可能正执行一条慢 UPDATE。
- 先通过
sys.innodb_lock_waits(更易读)拿到阻塞者的blocking_pid:SELECT blocking_pid FROM sys.innodb_lock_waits; - 再查其最近执行的 SQL:
SELECT sql_text FROM performance_schema.events_statements_history WHERE thread_id = ? ORDER BY event_id DESC LIMIT 1;(?替换为上一步得到的线程 ID) - 注意:
BLOCKING_ENGINE_TRANSACTION_ID≠INFORMATION_SCHEMA.INNODB_TRX.trx_id,需通过performance_schema.threads关联PROCESSLIST_ID才能找到真实会话
最容易被忽略的是:LOCK_DATA 字段只在 data_locks 中存在,且仅当事务持有行锁(非表锁)时才有值;如果看到大量 NULL,大概率是锁类型为 TABLE 或采集未覆盖到 InnoDB 层——这时该回头再核一遍 instrument 开关和存储引擎是否真为 InnoDB。











