查不到等待事件需先启用instruments和consumers:执行UPDATE performance_schema.setup_instruments SET ENABLED='YES' WHERE NAME LIKE 'wait/%';再执行UPDATE performance_schema.setup_consumers SET ENABLED='YES' WHERE NAME IN ('events_waits_current','events_waits_history_long')。

查不到等待事件?先确认 instruments 和 consumers 是否启用
Performance Schema 默认开启,但采集能力是“按需激活”的——setup_instruments 控制“采什么”,setup_consumers 控制“存到哪”。如果查 events_waits_current 返回空或全是 idle,大概率是这两类配置被禁用了。
常见错误现象:SELECT COUNT(*) FROM performance_schema.events_waits_current; 返回 0;或者只看到 wait/synch/mutex/sql/LOCK_thread_cache 这类低价值锁,看不到实际 IO 或行锁等待。
- 启用所有等待类采集器:
UPDATE performance_schema.setup_instruments SET ENABLED='YES', TIMED='YES' WHERE NAME LIKE 'wait/%'; - 启用对应消费者(必须):
UPDATE performance_schema.setup_consumers SET ENABLED='YES' WHERE NAME IN ('events_waits_current', 'events_waits_history_long'); - 注意:MySQL 8.0+ 中
events_waits_history默认关闭,建议直接用history_long,它保留最近 10000 条,更实用 - 修改后无需重启,但部分旧版本(如 5.7)可能需要执行
FLUSH STATUS;生效
死锁或长事务卡住?用 data_locks + data_lock_waits 连查阻塞链
MySQL 8.0 起,INNODB_LOCKS 和 INNODB_LOCK_WAITS 已废弃。靠 performance_schema.data_locks 和 data_lock_waits 才能拿到实时、可关联的锁关系。只看一张表等于只看半张拼图。
典型误操作:直接查 data_locks 想找“谁在等”,结果全是持锁记录,没等待信息。
- 先定位等待者和阻塞者:
SELECT REQUESTING_ENGINE_TRANSACTION_ID, BLOCKING_ENGINE_TRANSACTION_ID FROM performance_schema.data_lock_waits; - 再关联事务详情:
SELECT trx_id, trx_state, trx_started, trx_query FROM information_schema.INNODB_TRX WHERE trx_id IN (12345, 67890);(ID 来自上一步) -
data_locks中的THREAD_ID可连performance_schema.threads查会话来源,比如PROCESSLIST_ID或应用连接名 - 注意
LOCK_MODE值(如X,REC_NOT_GAP)和INDEX_NAME,它们决定是行锁还是间隙锁,直接影响是否可被其他事务绕过
SQL 执行慢但没报错?从 events_statements_history_long 挖真实耗时分布
slow_query_log 只捕获超过阈值的语句,而很多“亚秒级慢查询”(比如 300ms)会被漏掉。Performance Schema 的 events_statements_history_long 记录所有语句的完整生命周期指标,包括内存临时表、磁盘排序、锁等待时间等隐藏开销。
容易踩的坑:直接 SELECT * FROM events_statements_history_long 看得眼花,却忽略关键字段组合筛选。
- 重点看这三列:
TIMER_WAIT(总耗时)、LOCK_TIME(锁等待占比)、CREATED_TMP_DISK_TABLES(是否落盘) - 快速筛出高开销语句:
SELECT SQL_TEXT, sys.format_time(TIMER_WAIT), sys.format_time(LOCK_TIME), CREATED_TMP_DISK_TABLES FROM performance_schema.events_statements_history_long WHERE TIMER_WAIT > 100000000000 ORDER BY TIMER_WAIT DESC LIMIT 5;(单位是纳秒,1e11 ≈ 100ms) -
DIGEST_TEXT比SQL_TEXT更适合归类分析,相同模式不同参数的语句会被聚合成一条摘要,比如SELECT * FROM orders WHERE user_id = ? - 注意:该表默认只保留 10000 行,高频业务下可能被快速覆盖,必要时可调大
performance_schema_events_statements_history_long_size参数
全局读锁或 DDL 卡住?metadata_locks 是唯一实时证据源
当 FLUSH TABLES WITH READ LOCK 或长事务中执行 ALTER TABLE 时,整个库可能假死。传统 SHOW PROCESSLIST 只能看到“Waiting for table metadata lock”,但不知道谁在持锁、持了多久、锁在哪一级。
最常被忽略的一点:metadata_locks 表里 OWNER_THREAD_ID 不是会话 ID,而是内部线程 ID,必须通过 performance_schema.threads 关联才能定位真实连接。
- 查持锁者:
SELECT OBJECT_TYPE, OBJECT_SCHEMA, OBJECT_NAME, LOCK_TYPE, LOCK_DURATION, LOCK_STATUS, OWNER_THREAD_ID FROM performance_schema.metadata_locks WHERE LOCK_STATUS = 'GRANTED' AND OWNER_THREAD_ID != sys.ps_thread_id(CONNECTION_ID()); - 反查会话:
SELECT PROCESSLIST_ID, PROCESSLIST_USER, PROCESSLIST_HOST, PROCESSLIST_INFO FROM performance_schema.threads WHERE THREAD_ID = 42;(42 是上一步查到的 ID) - 特别注意
OBJECT_TYPE = 'GLOBAL'且LOCK_TYPE = 'SHARED'的记录,基本就是FTWRL的证据 - 云数据库(如 RDS)可能限制对
metadata_locks的访问权限,需确认账号有SELECTonperformance_schema.*
真正难的不是查哪张表,而是把 data_locks 的锁类型、threads 的会话上下文、INNODB_TRX 的事务状态这三条线索,在毫秒级变化中对齐。一次排查往往要交叉执行 4–5 个关联查询,顺序错了就看不到完整链路。


















