mysql 8.0 默认关闭锁相关instrument,需按顺序启用wait/lock、transaction及consumers,并验证至少10+行enabled;data_lock_waits仅记录瞬时阻塞,须在阻塞发生时查询,且仅对前台线程有效;需关联data_lock_waits、data_locks和innodb_trx三表定位sql与连接;mdl和备份锁不出现于data_locks,需单独查performance_schema.metadata_locks。

查不到data_locks或data_lock_waits,先确认采集器开了没
MySQL 8.0 默认关闭所有锁相关 instrument,data_locks 和 data_lock_waits 为空不是 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只记录“正在发生的阻塞”,不是历史日志
刚执行完 SELECT ... FOR UPDATE 就去查 data_lock_waits 却为空?大概率是因为锁已释放或阻塞尚未形成。它抓的是瞬时态,不是快照:
- 必须在阻塞“正在发生”时查询:会话 A 拿锁不提交,会话 B 被卡住,此时立即查
- 事务一提交、锁一释放,对应行就从
data_lock_waits消失 - 只对
TYPE = 'FOREGROUND'的线程有效(即普通客户端连接),复制线程、后台清理线程不会出现在结果里
关联data_locks和INNODB_TRX才能定位到具体 SQL 和连接
单看 data_lock_waits 只知道“谁在等谁”,但不知道是谁发的 SQL、连的是哪个应用。闭环排查必须三表联动:
-
data_lock_waits提供等待关系(REQUESTING_ENGINE_TRANSACTION_ID→BLOCKING_ENGINE_TRANSACTION_ID) -
data_locks提供锁对象细节(OBJECT_NAME、LOCK_DATA、LOCK_MODE) -
INNODB_TRX提供事务上下文(trx_mysql_thread_id、trx_query、trx_started)
典型关联方式:data_locks.ENGINE_TRANSACTION_ID = INNODB_TRX.trx_id;注意 INNODB_TRX 中 trx_state = 'RUNNING' 但 trx_query 为空的事务,往往是漏 commit/rollback 的“幽灵事务”,这才是线上锁等待的常见根因。
别漏掉元数据锁(MDL)和备份锁,它们不走data_locks
行锁容易被发现,但 DDL(如 ALTER TABLE)引发的元数据锁、LOCK INSTANCE FOR BACKUP 引发的备份锁,根本不出现在 data_locks 或 data_lock_waits 里:
- 查 MDL 阻塞用:
SELECT * FROM performance_schema.metadata_locks WHERE LOCK_STATUS = 'PENDING',再 JOINthreads找线程 - 查备份锁(8.0.22+)用:
SELECT * FROM performance_schema.metadata_locks WHERE OBJECT_TYPE = 'BACKUP' AND LOCK_STATUS = 'GRANTED',前提是performance_schema_metadata_locks_enabled = ON - 这两类锁都绕过 InnoDB 层,
data_locks对它们完全不可见
真正卡死线上服务的,往往不是 SELECT FOR UPDATE,而是某个 ALTER 正在等一个没人注意的 SELECT 持有的 MDL S 锁——这种场景下,只盯着 data_lock_waits 会彻底错过关键线索。











