查不到data_lock_waits是因锁采集未启用,需按序开启wait/lock%、transaction%类instrument及global_instrumentation等consumers,并验证至少10+行enabled;该视图仅记录瞬时阻塞,须关联data_locks和innodb_trx定位sql与连接。

查不到 data_lock_waits 或结果为空,基本不是 SQL 写错了,而是锁采集开关根本没开——这是 90% 的人卡住的第一步。
确认 performance_schema 锁采集已启用
MySQL 8.0 默认关闭所有锁相关 instrument,data_lock_waits 和 data_locks 是空的,不是 bug,是配置未生效。必须手动按顺序执行以下三步:
UPDATE performance_schema.setup_instruments SET ENABLED = 'YES', TIMED = 'YES' WHERE NAME LIKE 'wait/lock/%';UPDATE performance_schema.setup_instruments SET ENABLED = 'YES' WHERE NAME LIKE 'transaction%';UPDATE performance_schema.setup_consumers SET ENABLED = 'YES' WHERE NAME IN ('global_instrumentation', 'thread_instrumentation');
执行后立刻验证:SELECT COUNT(*) FROM performance_schema.setup_instruments WHERE NAME LIKE 'wait/lock/%' AND ENABLED = 'YES';——结果必须 ≥10,少于这个数,后续所有查询都注定为空。
用 data_lock_waits + data_locks 构建等待关系链
data_lock_waits 只存 ID 映射,不带库表名、SQL 或线程信息;单查它只能看到“谁在等谁”,看不出阻塞点在哪。必须关联 data_locks 才能补全锁对象细节:
-
REQUESTING_ENGINE_LOCK_ID关联data_locks.ENGINE_LOCK_ID→ 获取等待方锁的OBJECT_SCHEMA、OBJECT_NAME、LOCK_MODE、LOCK_DATA -
BLOCKING_ENGINE_LOCK_ID同样关联data_locks→ 获取持锁方锁的位置和模式 -
LOCK_MODE值要会读:S(共享)、X(排他)、GAP(间隙)、NEXT_KEY(临键);LOCK_DATA显示被锁的具体值或范围,比如10, 20就说明是间隙锁堵住了 INSERT
典型查询模板(带库表过滤):
SELECT r.OBJECT_SCHEMA, r.OBJECT_NAME, r.INDEX_NAME, r.LOCK_MODE AS requested_mode, b.LOCK_MODE AS blocking_mode, r.LOCK_DATA AS requested_data, b.LOCK_DATA AS blocking_data, w.REQUESTING_ENGINE_TRANSACTION_ID, w.BLOCKING_ENGINE_TRANSACTION_ID 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';
关联 INNODB_TRX 定位真实 SQL 和连接
知道“谁等谁”“锁在哪”还不够,得定位到具体是哪个应用、哪条 SQL、哪个连接在持锁。这一步必须连查三张表:
-
data_locks.ENGINE_TRANSACTION_ID对应INNODB_TRX.trx_id(注意:不是trx_mysql_thread_id) -
INNODB_TRX中重点看:trx_state = 'RUNNING'但trx_query IS NULL的事务——大概率是漏COMMIT/ROLLBACK的幽灵事务 -
trx_wait_started告诉你卡了多久;trx_started告诉你这个事务开了多久;两者差值大,说明早该结束了 - 别直接
KILL线程——先用performance_schema.threads查PROCESSLIST_INFO,确认不是监控探针或定时任务的“假活跃”连接
注意 data_lock_waits 的瞬时性与盲区
data_lock_waits 不是日志,是快照视图,只记录“正在发生的阻塞”:
- 会话 A 执行
SELECT ... FOR UPDATE后没提交,会话 B 被卡住 → 此时立即查data_lock_waits才有数据 - A 一
COMMIT或 B 超时退出,对应行立刻从data_lock_waits消失,查不到就是正常现象 - 只对
TYPE = 'FOREGROUND'的线程有效(即普通客户端连接),复制线程、后台 purge 线程不会出现在结果里 - MDL(元数据锁)和备份锁不走
data_locks,需单独查performance_schema.metadata_locks
真正难排查的,往往不是“查不到锁”,而是“查到了却不知道怎么闭环”——比如 LOCK_DATA 显示 NULL,或 INDEX_NAME 是 GEN_CLUST_INDEX,这时候得结合执行计划和索引结构反推加锁范围。











