MySQL默认不开启慢查询日志,且long_query_time默认10秒,对CPU飙升类问题无效;需设为0.1秒并启用log_queries_not_using_indexes以捕获高频低效SQL,再用pt-query-digest等工具分析Rows_examined异常高的语句。

确认慢查询日志是否开启且配置合理
MySQL 默认不开启慢查询日志,即使开了,long_query_time 默认是 10 秒,对 CPU 飙升类问题基本无效——这类 SQL 往往执行快但扫描行数巨大、频繁调用,或触发全表扫描+临时表+排序,单次耗时可能不到 1 秒。
必须调整为更敏感的阈值,例如 0.1 秒,并确保记录未使用索引的查询:
SET GLOBAL slow_query_log = ON; SET GLOBAL long_query_time = 0.1; SET GLOBAL log_queries_not_using_indexes = ON;
注意:long_query_time 在 MySQL 5.7+ 中支持微秒级(如 0.1),但需确认版本;log_queries_not_using_indexes 会显著增加日志量,仅在排查期启用,定位后及时关闭。
用 mysqldumpslow 或 pt-query-digest 快速聚合高频/高成本 SQL
原始慢日志体积大、重复多(比如带不同 WHERE id = ? 的同一模板),直接 grep 效率低。优先用工具归一化并排序:
-
mysqldumpslow -s c -t 10 /var/lib/mysql/slow.log:按出现次数(-s c)取 Top 10,快速发现高频语句 -
mysqldumpslow -s al -t 10 /var/lib/mysql/slow.log:按平均锁等待时间(-s al)排序,适合识别阻塞源头 - 更推荐
pt-query-digest(Percona Toolkit):能解析Rows_examined、tmp_tables、full_scan等关键指标,命令如:pt-query-digest /var/lib/mysql/slow.log --filter '$event->{Rows_examined} > 10000'
重点盯 Rows_examined 远大于 Rows_sent 的语句——说明扫描大量数据却只返回几行,极可能是缺失索引或 WHERE 条件未命中索引。
结合 SHOW PROFILE 或 performance_schema 定位执行瓶颈
找到可疑 SQL 后,不能只看“慢”,要拆解它卡在哪一步。在测试环境复现并启用分析:
- 用
SHOW PROFILE FOR QUERY N查看各阶段耗时(如Copying to tmp table、Sorting result) - 或开启
performance_schema并查events_statements_summary_by_digest,重点关注avg_timer_wait和sum_rows_examined - 务必检查
EXPLAIN FORMAT=JSON输出中的used_columns、using_filesort、using_temporary字段——这些是 CPU 消耗大户的明确信号
常见陷阱:ORDER BY 字段没索引、GROUP BY 涉及函数(如 DATE(created_at))、JOIN 时小表没走驱动表(EXPLAIN 中 table 列顺序反了)。
验证修复效果时别只看单条 SQL 耗时
加索引或改写 SQL 后,容易误判——单条 SELECT 可能变快了,但并发一上来 CPU 又拉满。必须观察整体负载变化:
- 用
top -p $(pgrep mysqld)或pidstat -p $(pgrep mysqld) 1实时看 mysqld 进程 CPU 使用率 - 对比修复前后
SHOW STATUS LIKE 'Threads_running'和'Queries'每秒增量 - 检查
information_schema.INNODB_METRICS中buffer_pool_reads、buffer_pool_read_requests比值是否下降(说明缓存效率提升)
最常被忽略的一点:某些“修复”只是把问题转移了,比如加了索引但导致 UPDATE/INSERT 变慢、引发更多锁等待,最终仍推高 CPU。得盯住业务端响应时间和错误率同步变化。

















