快速定位MySQL CPU飙升的慢查询需开启慢查询日志(long_query_time设为0.1)、用mysqldumpslow分析,再结合EXPLAIN、ANALYZE TABLE和索引设计综合排查。

怎么快速定位导致CPU飙升的慢查询
MySQL CPU高,八成是某条或几条查询在反复全表扫描、没走索引、或者生成了巨大临时表。别急着调参数,先抓“真凶”。SHOW PROCESSLIST 只能看当前活跃会话,容易漏掉已结束但耗时长的查询;真正管用的是开启慢查询日志并设低阈值。
- 用
SET GLOBAL slow_query_log = ON开启日志(需有 SUPER 权限) - 把
long_query_time设为0.1(单位秒),避免漏掉累积效应强的“中速”查询 - 确认日志路径:查
slow_query_log_file变量,别默认去 /var/lib/mysql/ 找——有些 Docker 镜像会写到 /dev/stdout 或容器外挂卷 - 用
mysqldumpslow -s t -t 10 /path/to/slow.log快速提取执行时间最长的前 10 条,注意看Count字段:高频低耗时查询也可能拖垮 CPU
EXPLAIN 看懂后为什么还是没走索引
EXPLAIN 显示 type=ALL 或 key=NULL 是典型信号,但原因常被误判。不是“加了索引就万事大吉”,MySQL 优化器会根据统计信息和代价估算跳过索引——尤其当它觉得走索引+回表比直接扫更快时。
- 检查
rows预估是否严重失真:运行ANALYZE TABLE table_name更新统计信息,旧版本 MySQL(如 5.6)对大表统计更新不及时 - 确认 WHERE 条件中的列是否在索引最左前缀上:
WHERE status = ? AND created_at > ?,而索引是(created_at, status),那status就无法有效利用 - 隐式类型转换会强制放弃索引:比如
user_id是BIGINT,但查询里写了WHERE user_id = '123'(字符串),MySQL 会转成函数式条件,索引失效 - 使用
FORCE INDEX临时验证:如果SELECT * FROM orders FORCE INDEX (idx_user_time) WHERE user_id = 123明显变快,说明优化器误判,该考虑重写查询或调整索引顺序
ORDER BY 和 GROUP BY 怎么避免 Using filesort / Using temporary
CPU 占用高的一大来源是排序和分组操作落在磁盘临时表或内存排序缓冲区(sort_buffer_size)里反复折腾。Using filesort 不一定慢,但配上大结果集或并发高,就会吃光 CPU。
- 确保
ORDER BY字段包含在索引中,且顺序与索引定义一致:比如ORDER BY a ASC, b DESC,MySQL 8.0+ 才支持混合方向索引,5.7 及以前必须全 ASC 或全 DESC -
GROUP BY尽量复用索引覆盖:如果SELECT a, COUNT(*) FROM t GROUP BY a,索引(a)就够;但若写成SELECT a, b, COUNT(*),而索引只有(a),就会触发Using temporary - 避免在
ORDER BY中用函数或表达式:ORDER BY UPPER(name)无法利用name索引,可建函数索引(MySQL 8.0+)或冗余字段预计算 - 检查
tmp_table_size和max_heap_table_size是否太小:二者取较小值,决定内存临时表上限;设太小会导致频繁落磁盘,Created_tmp_disk_tables值飙升
哪些“优化”反而会让CPU更累
有些常见操作本意是提速,实则增加解析、锁竞争或缓存失效压力,最终推高 CPU。尤其在线上环境改之前,务必在从库或压测环境验证。
- 盲目加
SQL_NO_CACHE(MySQL 5.7 已废弃)或SELECT SQL_CALC_FOUND_ROWS:前者干扰查询缓存机制(即使禁用也多一次判断),后者强制全扫计数,比分开COUNT(*)+ 分页查询更重 - 用
UUID或随机字符串做主键:插入时 B+ 树频繁分裂、页合并,CPU 花在维护索引结构上远超查询本身;自增BIGINT仍是高并发写场景最稳选择 - 在
WHERE里大量用OR连接不同字段:WHERE a = 1 OR b = 2很难命中单个索引,优化器可能干脆放弃索引;拆成UNION ALL并确保各分支能独立走索引,效果更好 - 过度依赖
pt-query-digest分析慢日志:它本身是 Perl 脚本,处理 GB 级日志时 CPU 占用可观——优先用mysqldumpslow快筛,再针对具体语句深入
慢查询背后往往不是单点问题,而是索引设计、数据分布、查询写法、服务器配置四者咬合的结果。盯着一条 EXPLAIN 输出调参,不如花十分钟看懂这张表最近一周的 Handler_read_* 指标变化。很多“高 CPU”其实在日志里早有迹可循,只是没连起来看。


















