查data_lock_waits返回空不等于无锁争用,仅表示当前无实时等待对;持锁但无人等待、间隙锁未触发冲突、锁刚释放等情况均导致该表为空,需结合data_locks、INNODB_TRX等综合分析。

查 data_lock_waits 返回空,是不是就没锁争用?
不是。空结果只代表“此刻没有正在发生的等待对”,不等于没锁、没争用、没隐患。
常见错误现象:SELECT * FROM performance_schema.data_lock_waits\G 什么也不返回,就以为系统很健康;结果过几分钟突然卡住,SHOW PROCESSLIST 里一堆 Waiting for table metadata lock 或 Locked 状态。
-
data_lock_waits只记录BLOCKING_TRX_ID和REQUESTING_TRX_ID同时存在且尚未释放的实时等待关系 - 如果一个事务持锁但没人等它(比如长事务执行完
SELECT FOR UPDATE后一直没提交),data_lock_waits就是空的,但data_locks里肯定有它的锁记录 - 间隙锁(GAP)、Next-Key 锁在冲突未触发前不会生成等待条目,但已真实加锁——此时
data_lock_waits为空,data_locks却有大量LOCK_MODE: X,GAP - 锁刚释放、等待刚解除,该表可能已清空,但
INFORMATION_SCHEMA.INNODB_TRX仍能查到未提交事务
为什么开了 performance_schema,data_locks 还是空?
因为 InnoDB 锁采集不是默认开启的,必须手动启用对应 instrument。
使用场景:MySQL 8.0+ 默认关闭锁相关 instrument,哪怕 performance_schema = ON,data_locks 和 data_lock_waits 也始终为空表。
- 执行
SELECT * FROM performance_schema.setup_instruments WHERE NAME LIKE 'wait/lock/innodb%'; - 确认
wait/lock/innodb/innodb_lock_monitor的ENABLED列为YES;若为NO,需执行UPDATE performance_schema.setup_instruments SET ENABLED = 'YES' WHERE NAME = 'wait/lock/innodb/innodb_lock_monitor'; - 注意:修改后无需重启 MySQL,但只对新建立的连接生效;已有连接的锁不会被补录
- 该 instrument 开启后有一定性能开销(尤其高并发短事务场景),不建议长期全量开启,排障时临时启用即可
怎么从 data_locks 定位到具体是哪条 SQL 在持锁?
单看 data_locks 只知道锁了哪张表、哪个索引、什么模式,但不知道是谁、干了什么。必须串联三张表才能闭环。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
关键步骤:
- 从
data_locks提取THREAD_ID和LOCK_DATA(行锁时可能是主键值,GAP 锁会显示supremum pseudo-record) - 用
THREAD_ID关联performance_schema.threads,过滤TYPE = 'FOREGROUND'(排除后台线程),拿到PROCESSLIST_ID(即SHOW PROCESSLIST中看到的 ID) - 再用同一
THREAD_ID查performance_schema.events_statements_current.SQL_TEXT——但要注意:如果事务已执行完语句、处于 sleep 状态,这里会是NULL - 此时必须 fallback 到
INFORMATION_SCHEMA.INNODB_TRX,用TRX_MYSQL_THREAD_ID关联PROCESSLIST_ID,查TRX_QUERY和TRX_STARTED时间,人工比对活跃窗口
LOCK_DURATION = 'TRANSACTION' 的 MDL 锁为什么最危险?
元数据锁(MDL)生命周期由 LOCK_DURATION 决定,而 TRANSACTION 级别意味着:只要事务没提交或回滚,锁就一直挂着,哪怕你只执行了一条 SELECT。
容易踩的坑:
- ORM 框架自动
BEGIN,但异常路径下忘记ROLLBACK,导致 MDL 锁长期滞留 -
autocommit = 0配置下,HTTP 请求处理完没显式COMMIT,连接池复用后下一个请求继续沿用这个“半死不活”的事务上下文 -
ALTER TABLE等 DDL 操作需要MDL_EXCLUSIVE,一旦被前面的TRANSACTION级 MDL 阻塞,整个表就不可读写 - 这类锁不会出现在
data_lock_waits(它是元数据锁,非数据锁),只能通过performance_schema.metadata_locks查,且必须确保wait/lock/metadata/sql/mdlinstrument 已启用
真正难定位的不是锁本身,而是那个“什么都没干却一直占着茅坑”的事务——它往往藏在连接池背后,SQL_TEXT 为空,TRX_QUERY 为 NULL,只能靠 TRX_STARTED 时间和应用日志交叉印证。










