必须先启用wait/lock和transaction相关instrument及consumers,否则data_lock_waits为空是配置未生效而非bug;该表仅记录瞬时阻塞,需在阻塞发生时立即查询,并关联data_locks和INNODB_TRX定位SQL与连接。

查 data_lock_waits 前必须确认 instrument 已启用
空表不是 bug,是采集开关没开。MySQL 默认关闭锁等待相关的 instrument,data_lock_waits 和 data_locks 表即使存在,也始终返回空结果。
- 执行
SELECT * FROM performance_schema.setup_instruments WHERE NAME LIKE 'wait/lock%';,检查ENABLED列是否为YES - 若为
NO,运行UPDATE performance_schema.setup_instruments SET ENABLED = 'YES' WHERE NAME LIKE 'wait/lock%'; - 注意:部分老版本(如 5.7.30 之前)需在配置文件中加
performance_schema_instrument = 'wait/lock%=ON'并重启 mysqld -
wait/innodb/innodb_lock_wait是另一关键 instrument,不启用它就捕获不到 InnoDB 层的锁等待事件,仅靠data_lock_waits会漏掉大量瞬时竞争
用 data_lock_waits + data_locks 定位“等什么锁”
data_lock_waits 只告诉你谁在等谁,但不告诉你等的是哪张表、哪个索引、什么类型——这些全在 data_locks 里,必须 JOIN 才能闭环。
- 典型查询:
SELECT w.OBJECT_SCHEMA, w.OBJECT_NAME, w.INDEX_NAME, w.LOCK_MODE, w.LOCK_TYPE, 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字段显示具体值(如123)或范围(如10, 20),对诊断间隙锁阻塞 INSERT 至关重要 - 别直接用
BLOCKING_ENGINE_TRANSACTION_ID去查INNODB_TRX.trx_id:二者 ID 不同源,必须通过performance_schema.threads的THREAD_ID关联才能找到真实连接和PROCESSLIST_INFO
关联 INNODB_TRX 找出“持锁者在干啥”
知道锁对象还不够,得知道阻塞方事务当前状态和 SQL。很多卡顿根源不是并发高,而是某个事务早该结束了却一直挂着。
- 查活跃事务:
SELECT trx_id, trx_state, trx_started, trx_mysql_thread_id, trx_query, trx_operation_state FROM information_schema.INNODB_TRX WHERE trx_state = 'RUNNING' AND (trx_query IS NULL OR trx_query = '') ORDER BY trx_started ASC LIMIT 5; - 重点关注
trx_operation_state = 'sleeping before entering InnoDB'的事务——这通常是应用断连后残留的“僵尸事务”,持有锁却不执行任何 SQL - 若
trx_query非空,再用trx_mysql_thread_id去performance_schema.threads查PROCESSLIST_INFO,确认是不是监控探针、定时任务或已超时的 HTTP 请求连接 - RR 隔离级别下,
SELECT ... FOR UPDATE后未提交就会持续持锁;RC 下虽释放快些,但唯一键冲突检查仍可能触发间隙锁残留
为什么 SHOW ENGINE INNODB STATUS\G 还不能丢
它仍是唯一能拿到死锁图谱(包括每个事务持有的所有锁、等待的锁、SQL 堆栈、索引扫描路径)的轻量工具,且无需任何配置。
- 输出中只看
LATEST DETECTED DEADLOCK块,其他全是干扰信息 - 关键字段:
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:显示等待的锁类型和索引;*** (2) HOLDS THE LOCK(S):显示已持有哪些锁;mysql tables in use和HEAP tables in use可辅助判断是否涉及临时表或隐式锁升级 - 它不反映实时等待链,只记录最近一次死锁;但当你怀疑是“两个事务反复争同一行”时,它的堆栈比
data_lock_waits更直观 - 注意:该命令是快照,执行瞬间可能错过正在发生的等待;而
data_lock_waits是动态视图,但依赖 instrument 开启状态——两者互补,不是替代关系
真正容易被忽略的点是:锁等待链不是静态拓扑,而是随事务推进实时消长的。你看到的 REQUESTING_ENGINE_TRANSACTION_ID → BLOCKING_ENGINE_TRANSACTION_ID 关系,可能在查询执行完的下一毫秒就因 COMMIT 或 ROLLBACK 而消失。所以排查必须快,且所有查询最好在几秒内串起来执行,中间穿插 SELECT SLEEP(0.1) 反而可能错过关键窗口。


















