查不到events_waits_history_long里的锁等待,先确认wait/innodb/innodb_lock_wait事件是否启用:默认为D(Disabled),需手动UPDATE setup_instruments启用ENABLED和TIMED,并开启events_waits_history_long consumer,修改后仅新连接生效。

查不到events_waits_history_long里的锁等待?先确认采集开关开了没
很多排查卡在第一步:表里有数据但wait/innodb/innodb_lock_wait事件始终为空。这不是SQL写错,而是instrument默认关闭。MySQL 5.7+ 中该事件默认状态是D(Disabled),哪怕performance_schema整体开着也没用。
执行这条语句检查:
SELECT * FROM performance_schema.setup_instruments WHERE NAME = 'wait/innodb/innodb_lock_wait';
若ENABLED或TIMED为NO,需立即启用:
UPDATE performance_schema.setup_instruments SET ENABLED = 'YES', TIMED = 'YES' WHERE NAME = 'wait/innodb/innodb_lock_wait';- 同时确保对应consumer开启:
UPDATE performance_schema.setup_consumers SET ENABLED = 'YES' WHERE NAME = 'events_waits_history_long'; - 注意:修改后新连接才生效,旧会话不会自动继承
为什么events_waits_history_long里看到的耗时不准或为0?
events_waits_history_long记录的是“等待事件”的真实耗时,但它只捕获从发起等待到获取锁之间的间隙——不包括事务本身执行SQL的时间,也不包括锁被持有期间的空等。所以你可能看到:
- 某条
UPDATE执行了2秒,但wait/innodb/innodb_lock_wait只记录了150ms——说明它只等了150ms就拿到了锁,剩下时间花在InnoDB内部处理上 - 耗时列为
0:常见于极短等待(低于采样精度)或锁立刻命中(无竞争) - 同一事务多次出现该事件:InnoDB对单条语句可能分阶段加锁(如先查索引再更新记录),每次等待单独计时
真正反映“锁拖慢业务”的,是SOURCE列(如row0sel.cc:3420)和NESTING_EVENT_ID——它能帮你把等待事件回溯到具体的events_statements_current中的SQL
如何关联锁等待和具体SQL?别只查events_waits_history_long
单独看events_waits_history_long只能知道“某个线程在等锁”,但不知道它在跑哪条SQL、谁在挡路。必须三表联查:
SELECT s.THREAD_ID, s.SQL_TEXT, w.EVENT_NAME, w.SOURCE, w.TIMER_WAIT / 1000000000 AS wait_sec, w.NESTING_EVENT_ID FROM performance_schema.events_waits_history_long w JOIN performance_schema.events_statements_current s ON w.THREAD_ID = s.THREAD_ID AND w.NESTING_EVENT_ID = s.EVENT_ID WHERE w.EVENT_NAME = 'wait/innodb/innodb_lock_wait' ORDER BY w.TIMER_WAIT DESC LIMIT 10;
关键点:
-
NESTING_EVENT_ID必须严格等于events_statements_current.EVENT_ID,不能只靠THREAD_ID匹配(一个线程可能有多个活跃语句) -
SQL_TEXT字段在MySQL 8.0+默认被截断,需提前设置performance_schema_max_sql_text_length参数(如设为1024) - 若
SQL_TEXT为空,说明该语句已结束,此时应查events_statements_history_long找历史快照
锁等待耗时高,但data_lock_waits没记录?说明不是行锁问题
performance_schema.data_lock_waits只记录InnoDB层的**行级锁等待关系**,而events_waits_history_long中的wait/innodb/innodb_lock_wait事件涵盖更广:它也包括意向锁冲突、元数据锁(wait/synch/mutex/sql/LOCK_open)、甚至部分缓冲池争用。
如果你发现:
-
events_waits_history_long里wait/innodb/innodb_lock_wait耗时很高 - 但
data_lock_waits为空,且data_locks中没有对应事务的锁记录
那大概率不是行锁阻塞,而是:
- DDL操作引发的
metadata lock(比如另一个会话正在ALTER TABLE) - 全表扫描导致的意向锁升级冲突(缺少索引,退化为表级争用)
- InnoDB内部资源争用(如
log_sys_mutex、buf_pool_mutex),这时要查wait/synch/mutex/innodb/类事件
真正的行锁争用,一定能在data_locks和data_lock_waits里找到匹配的ENGINE_TRANSACTION_ID和锁对象信息——否则别在行锁路径上死磕。


















