必须先启用InnoDB锁采集instrument和consumers,否则data_locks为空;其LOCK_TYPE='RECORD'、LOCK_MODE(含GAP/NEXT_KEY)及LOCK_DATA范围可定位行锁热点;需关联threads和events_statements_current或INNODB_TRX定位持锁者。

查 data_locks 前先确认锁采集已启用
不启用 wait/lock/innodb/innodb_lock_monitor,data_locks 就是空表——不是没行锁,是根本没记。MySQL 8.0 默认关闭锁级 instrument,必须手动打开:
UPDATE performance_schema.setup_instruments SET ENABLED = 'YES', TIMED = 'YES' WHERE NAME LIKE 'wait/lock/innodb/%';UPDATE performance_schema.setup_consumers SET ENABLED = 'YES' WHERE NAME IN ('events_waits_current', 'events_waits_history_long');- 执行后立即生效,无需重启(MySQL 8.0.16+ 支持动态启停)
常见错误:只开 setup_consumers 忘了开 setup_instruments,结果查 data_locks 仍为空;或开了 wait/lock/external/% 却漏掉 innodb 分支,导致 InnoDB 行锁完全不采集。
从 data_locks 识别真实行锁压力点
data_locks 不是“锁了多少次”,而是“当前持有哪些锁”。它的关键字段直接反映行锁开销来源:
-
LOCK_TYPE = 'RECORD'表示行锁(含间隙锁、临键锁),不是表锁或元数据锁 -
LOCK_MODE值要会读:S(共享)、X(排他)、REC_NOT_GAP(纯记录)、GAP(间隙)、NEXT_KEY(临键)——间隙锁和临键锁易引发隐式阻塞,但不产生data_lock_waits记录 -
LOCK_DATA显示具体值(如123)或范围(如10, 20),高频出现相同范围说明业务存在热点区间(如时间戳递增主键 + 范围查询) -
OBJECT_SCHEMA和OBJECT_NAME可快速定位哪张表锁最密集;若某表data_locks行数远超其他表,且LOCK_DURATION = 'TRANSACTION'占比高,说明事务未及时提交
关联 threads 和 events_statements_current 定位“谁在锁”
单看 data_locks 只知道“锁了什么”,不知道“谁锁的、为什么锁”。THREAD_ID 是内部 ID,不能直接对应 SHOW PROCESSLIST 的 ID:
- 用
data_locks.THREAD_ID关联performance_schema.threads,取PROCESSLIST_ID(即 show processlist 中的 ID)和TYPE = 'FOREGROUND'(排除后台线程) - 再用同一
THREAD_ID查events_statements_current.SQL_TEXT——但注意:如果事务处于 sleep 状态,这里为NULL,此时必须 fallback 到INFORMATION_SCHEMA.INNODB_TRX查TRX_QUERY和TRX_STARTED,人工比对活跃时间窗口 - 若
SQL_TEXT是SELECT ... FOR UPDATE或隐式开启事务的INSERT,且TRX_STATE = 'RUNNING',基本可判定该语句长期持有行锁
结合 events_waits_summary_global_by_event_name 看锁等待总量
data_locks 是快照,events_waits_summary_global_by_event_name 是累计统计,两者互补:
- 执行
SELECT EVENT_NAME, COUNT_STAR, SUM_TIMER_WAIT FROM performance_schema.events_waits_summary_global_by_event_name WHERE EVENT_NAME LIKE 'wait/lock/innodb/%' ORDER BY SUM_TIMER_WAIT DESC LIMIT 5; - 重点关注
wait/lock/innodb/row_lock_s(共享行锁等待)、wait/lock/innodb/row_lock_x(排他行锁等待)的COUNT_STAR是否突增——这代表单位时间内行锁冲突频次升高,而非单次锁持有时间变长 - 若
SUM_TIMER_WAIT高但COUNT_STAR低,说明个别事务锁持有太久(如长事务未提交);若两者都高,更可能是并发写入热点行(如计数器更新、库存扣减) - 注意:该表不区分具体表或索引,仅作趋势判断;真正归因仍需回到
data_locks+threads链路
最易被忽略的是 LOCK_MODE 和 LOCK_DATA 的组合含义:比如 LOCK_MODE = 'X,GAP' 且 LOCK_DATA = 'supremum pseudo-record',说明事务在索引末尾加了间隙锁,后续 INSERT 可能被堵住,但 data_lock_waits 里可能查不到等待者——因为还没人真去插那条记录。


















