MySQL profiling需先执行SET profiling = 1;,仅对当前会话生效,记录最近15条语句各阶段耗时,用SHOW PROFILE FOR QUERY N;查看详细阶段;其Duration不含网络、锁等待等外部延迟,且数据随连接断开而丢失。

怎么开 profiling 看单条 SQL 的各阶段耗时
MySQL 自带的 profiling 功能能拆解一条语句从解析、优化、执行到发送结果的每个阶段耗时,但默认关闭,且只对当前会话生效。打开后,它记录的是最近 15 条语句(可调),不是全局实时监控。
- 先执行
SET profiling = 1;,之后本会话所有语句都会被记录 - 跑你要分析的 SQL,比如
SELECT * FROM orders WHERE status = 'paid' LIMIT 100; - 再查
SHOW PROFILES;看语句编号和总耗时 - 用
SHOW PROFILE FOR QUERY N;(N 是上一步看到的 Query_ID)看详细阶段,比如executing、Sorting result、sending data
注意:profiling 在 MySQL 8.0.22+ 已被标记为 deprecated,虽仍可用,但官方建议迁移到 Performance Schema;不过对快速定位某条慢 SQL 的瓶颈点,它仍是最快上手的工具。
为什么 SHOW PROFILE 显示的 “Duration” 和实际执行时间对不上
常见现象是 SHOW PROFILE 里加起来才 20ms,但客户端测出来花了 300ms——这不是数据错,而是它只统计服务器内部阶段,不包含网络传输、客户端解析、连接等待、锁等待(如被其他事务 block)等外部延迟。
-
Duration列是 MySQL 引擎层真正干活的时间,不含上下文切换或系统调度抖动 - 如果看到
Waiting for table metadata lock或Waiting for global read lock这类状态,说明卡在锁上,但 profiling 不会把等待时间算进Duration,得去查information_schema.INNODB_TRX或performance_schema.data_locks - 若语句用了临时表或磁盘排序(
Creating tmp table/Copying to tmp table on disk),对应阶段耗时会明显拉长,这是真实性能问题信号
Performance Schema 替代方案:怎么查更细粒度的执行链路
MySQL 5.6+ 的 Performance Schema 是 profiling 的继任者,支持开启语句级、阶段级甚至锁级事件采集,但默认很多消费者(consumers)是关的,直接查可能返回空。
- 先确认是否启用:
SELECT * FROM performance_schema.setup_consumers WHERE NAME LIKE '%events%';,把events_statements_history_long和events_stages_history_long设为ENABLED - 开采集:
UPDATE performance_schema.setup_instruments SET ENABLED = 'YES' WHERE NAME LIKE 'statement/%' OR NAME LIKE 'stage/%'; - 执行目标 SQL 后,查
SELECT * FROM performance_schema.events_statements_history_long ORDER BY TIMER_START DESC LIMIT 1;找到它的EVENT_ID,再用这个 ID 去events_stages_history_long查各阶段耗时
比 profiling 多出的关键信息包括:是否走了索引、扫描行数(ROWS_EXAMINED)、临时表使用量、是否触发了 filesort——这些在 profiling 里全看不到。
容易被忽略的坑:profiling 数据只存在内存,一断连就清空
很多人开了 profiling,跑完 SQL 就切到别的终端查 SHOW PROFILES,结果为空。这是因为 profiling 数据绑定在当前连接(connection)生命周期内,连接断开或超时,记录全丢。
- 别在脚本里开 profiling 后立刻退出连接;要查就得在同一个 shell 或客户端 session 里连续操作
-
SHOW PROFILE默认只显示前 15 条,想看更多得改系统变量:SET SESSION profiling_history_size = 100;(最大 100) - 线上环境慎用:虽然开销极小,但频繁启停 profiling + 大量查询会略微增加线程本地内存分配压力,高并发下可能放大 context switch
真要长期监控,别依赖 profiling,该上 slow log 配合 pt-query-digest,或者用 Performance Schema 持久化到表里——但那就得自己写采集逻辑了。










