mysql profile 不记录锁等待时间,其 duration 仅统计引擎内部执行耗时,无法反映 waiting for table metadata lock 等锁等待;官方已弃用,推荐改用 performance schema 精确分离执行与等待时间。

MySQL Profile 无法分析事务中各阶段的锁耗时——它根本不记录锁等待时间,所有 Waiting for xxx lock 类状态(如 Waiting for table metadata lock、Waiting for global read lock)在 SHOW PROFILE FOR QUERY N 的 Duration 列里完全不体现。
为什么 Profile 显示的耗时和实际卡顿对不上
Profile 的 Duration 只统计 MySQL 引擎内部“真正在干活”的时间,比如解析 SQL、读取索引页、排序结果集。一旦语句被锁住(例如另一个事务占着 user 表没提交),当前会话就停在 System lock 或 Waiting for table metadata lock 阶段,但这个等待过程不会计入任何 Duration 值。
常见误判现象:
- 客户端测出执行花了 2.3 秒,
SHOW PROFILE FOR QUERY N所有阶段加起来才 8ms → 实际是卡在锁上,Profile 没告诉你 -
executing阶段耗时异常高(比如 1.8 秒)→ 很可能不是执行慢,而是它把锁等待时间错误地塞进了这个阶段(尤其在旧版本中) - 看到
Creating sort index耗时长 → 真实原因是ORDER BY没走索引,但若同时存在锁竞争,Profile 完全掩盖了这点
想看锁耗时,必须换用 Performance Schema
Profile 已在 MySQL 5.7 标记为 deprecated、8.0 彻底移除,官方明确推荐用 Performance Schema 替代。它能真实分离“执行时间”和“等待时间”:
- 查锁等待:需开启
events_waits_history_long和对应 instrument,比如wait/lock/metadata/sql/mdl - 关联事务:通过
EVENT_ID关联events_statements_history_long和events_waits_history_long,才能定位某条 SQL 在哪个阶段等了多久锁 - 关键字段是
TIMER_WAIT(单位皮秒),不是TIMER_START;直接看数字容易误判,要除以1000000000000转成秒 - 子查询、存储过程调用会生成多个
EVENT_ID,不能只盯最外层语句
快速现场排查锁问题的替代方案
比起折腾 Profile 或 PFS,线上事务卡顿优先用更轻量、更准的方式:
- 开慢日志并设低阈值:
SET GLOBAL long_query_time = 0.1;+SET GLOBAL log_slow_extra = ON;(MySQL 8.0.26+)→ 日志里直接有Lock_time字段 - 实时查阻塞源:
SELECT * FROM performance_schema.data_locks;和SELECT * FROM information_schema.INNODB_TRX WHERE TRX_STATE = 'LOCK WAIT'; - 用
pt-deadlock-logger持续捕获死锁,比人工翻日志快得多 - 避免在事务里混用 DDL(如
ALTER TABLE)和 DML,DDL 会持 MDL 锁,Profile 完全不反映这类代价
Profile 的阶段名(如 init、optimizing)是真实行为证据,但仅限引擎内动作;锁、网络、客户端解析这些外部延迟,它既不采集,也不提示——这点最容易被忽略。











