TOP云物理服务器特惠,CPU可选双路E5-2660(32核)、双路E5-2680v2(40核)、双路E5-2696/98 V4(88核)、双路Gold 6138(80核)、双路Platinum 8173(112核);
内存从32G-128G可选,带宽有单线、多线独享20M-200M,价格低至368元。
购买链接:https://c.topyun.vip/cart?fid=1&gid=236
云主机MySQL CPU占用异常?慢查询与索引缺失排查
当云主机的MySQL数据库CPU使用率突然飙升至90%以上,甚至接近100%,而业务流量并未出现明显增长时,最常见的原因之一就是慢查询或索引缺失。MySQL CPU使用率过高会导致数据读写处理缓慢、连接超时、无法获取数据库连接等问题,严重影响业务正常运行。本文将系统讲解如何通过慢查询日志定位问题SQL,并利用EXPLAIN分析执行计划,排查索引缺失,从而彻底解决CPU异常占用问题。
一、MySQL CPU高占用的核心原因
1. 慢查询导致CPU飙升
慢查询是MySQL CPU使用率过高的最常见原因。当查询执行效率低、需要扫描大量数据时,为获得预期的结果需要访问大量数据,导致平均逻辑IO高,即使在QPS(每秒查询数)并不高的情况下,也会导致实例的CPU使用率偏高。典型的慢查询场景包括:复杂的JOIN操作、ORDER BY/GROUP BY排序、未命中索引的大表全表扫描、临时表使用等。
2. 索引缺失或失效
索引缺失是导致全表扫描的直接原因。当MySQL无法使用索引进行数据过滤时,必须扫描大量数据行,造成CPU资源被大量消耗。具体表现为:Rows_examined(扫描行数)远大于Rows_sent(返回行数),扫描大量行却返回少量数据,说明过滤效率低,大概率缺索引或索引失效。
3. 高QPS压垮CPU
如果查询本身执行效率高,但QPS过高,CPU也会被占满。例如4核服务器支撑20k-30k的点查询,每个SQL占用CPU时间并不多,但整体QPS很高,CPU时间也会被占满。
二、开启慢查询日志:捕获”元凶”
1. 配置慢查询参数
MySQL慢查询日志默认是关闭的,需手动开启并合理设置阈值。核心参数配置如下:
-- 开启慢查询日志(立即生效)
SET GLOBAL slow_query_log = 'ON';
-- 设置慢查询阈值(单位:秒),建议设为0.5-1秒
SET GLOBAL long_query_time = 0.5;
-- 指定日志文件路径
SET GLOBAL slow_query_log_file = '/var/log/mysql/mysql-slow.log';
-- 记录未使用索引的查询(强烈建议开启)
SET GLOBAL log_queries_not_using_indexes = 'ON';
也可在my.cnf配置文件中永久启用:
[mysqld]
slow_query_log = 1
slow_query_log_file = /var/log/mysql/mysql-slow.log
long_query_time = 0.5
log_queries_not_using_indexes = 1
2. 解读慢查询日志条目
一条典型的慢查询日志条目格式如下:
# Time: 2026-03-31T10:00:00.000000Z
# User@Host: webapp[webapp] @ localhost [] Id: 101
# Query_time: 3.215000 Lock_time: 0.001200
# Rows_sent: 5 Rows_examined: 820000
SET timestamp=1774951200;
SELECT * FROM products WHERE category_id = 7 AND active = 1;
关键字段解读:
- Query_time:SQL总执行时间(秒),超过阈值的都会被记录。
- Rows_examined:MySQL扫描的行数,核心指标之一。
- Rows_sent:实际返回给客户端的行数。
一个重要的判断原则:如果Rows_examined远大于Rows_sent,说明扫描了大量行才返回少量数据,这是一个明确的信号——查询需要更好的索引。
三、使用工具分析慢查询日志
1. mysqldumpslow(MySQL自带)
mysqldumpslow是MySQL自带的日志分析工具,可以聚合和汇总慢查询日志内容。常用命令如下:
# 按查询时间排序,显示前10条
mysqldumpslow -s t -t 10 /var/log/mysql/mysql-slow.log
# 按执行次数排序(最频繁的查询)
mysqldumpslow -s c -t 10 /var/log/mysql/mysql-slow.log
# 按平均查询时间排序
mysqldumpslow -s at -t 10 /var/log/mysql/mysql-slow.log
2. pt-query-digest(Percona Toolkit,推荐)
pt-query-digest是业界标准的高级分析工具,功能更强大,输出报告详细:
# 生成完整分析报告
pt-query-digest /var/log/mysql/mysql-slow.log > slow_report.txt
# 分析最近24小时的慢查询
pt-query-digest --since '24h' /var/log/mysql/mysql-slow.log
pt-query-digest的输出会按”总耗时”排序,告诉你哪些SQL消耗了最多的数据库时间。排名第一的那个,就是你需要优化的头号目标。
四、使用EXPLAIN分析执行计划
定位到可疑慢SQL后,使用EXPLAIN命令分析其执行计划,是定位索引问题的关键技术。
EXPLAIN SELECT * FROM products WHERE category_id = 7 AND active = 1\G
重点关注以下字段:
| 字段 | 含义 | 优化方向 |
|---|---|---|
| type | 访问类型(从好到坏:system > const > eq_ref > ref > range > index > ALL) | 出现ALL表示全表扫描,必须优化 |
| key | 实际使用的索引 | 若为NULL,说明未命中索引 |
| rows | 预估扫描的行数 | 越小越好,远大于预期结果集说明索引选择性差 |
| Extra | 附加信息 | 出现Using filesort或Using temporary是性能红灯 |
EXPLAIN FORMAT=JSON 可以提供更详细的成本估算信息:
EXPLAIN FORMAT=JSON SELECT * FROM products WHERE category_id = 7 AND active = 1\G
五、常见索引缺失与优化场景
场景一:全表扫描
日志特征:Query_time长,Rows_examined远大于Rows_sent
示例日志:
# Query_time: 12.5 Lock_time: 0.1
# Rows_sent: 10 Rows_examined: 5000000
SELECT * FROM orders WHERE status = 'PENDING';
EXPLAIN结果:type = ALL(全表扫描)
优化方案:为status列添加索引,或创建复合索引(status, created_at)
场景二:索引失效(隐式类型转换)
日志特征:Rows_examined大,但执行计划显示索引未使用
示例:mobile字段定义为VARCHAR,但查询使用数字常量:
SELECT * FROM user WHERE mobile = 13800138000; -- 错误!应使用引号
优化方案:改为WHERE mobile = '13800138000',避免隐式类型转换导致的索引失效
场景三:排序不合理
日志特征:Extra中出现Using filesort
SELECT * FROM product ORDER BY sales DESC LIMIT 10;
优化方案:在sales列上建立索引,或使用覆盖索引避免回表
场景四:未使用索引的查询
即使执行时间不到1秒,但无索引的查询在log_queries_not_using_indexes开启后也会被捕获:
# Query_time: 0.3 Rows_examined: 500000
SELECT id, name FROM category WHERE parent_id = 10;
优化方案:为parent_id建立索引
六、索引优化实战策略
1. 为WHERE + ORDER BY组合建联合索引
遵循”过滤字段在前、排序字段在后”的原则。例如,对于查询:
SELECT * FROM orders WHERE status = 1 ORDER BY created_at DESC;
适合创建复合索引(status, created_at)。
2. 使用覆盖索引
覆盖索引让查询的所有字段都包含在索引中,避免回表操作,可显著降低CPU消耗。例如:
-- 如果只查询 id 和 name,可以创建复合索引
ALTER TABLE users ADD INDEX idx_id_name (id, name);
3. 合理调整索引
添加合适的索引:为WHERE、JOIN、ORDER BY、GROUP BY字段添加索引
优化复合索引顺序:将最频繁使用的列放在左侧
避免过度索引:索引并非越多越好,会产生额外的维护开销
定期重建碎片化索引:使用OPTIMIZE TABLE语句
七、排查标准流程
| 步骤 | 操作 | 关键命令/工具 |
|---|---|---|
| 第一步 | 查看当前正在执行的查询 | SHOW FULL PROCESSLIST;,关注Time列和State列 |
| 第二步 | 确认CPU使用率 | 查看云监控或执行top命令 |
| 第三步 | 开启慢查询日志 | SET GLOBAL slow_query_log = 'ON'; |
| 第四步 | 收集一段时间慢查询数据 | 建议收集1小时以上 |
| 第五步 | 使用分析工具定位 | pt-query-digest或mysqldumpslow |
| 第六步 | 对目标SQL执行EXPLAIN | EXPLAIN FORMAT=JSON SELECT ...; |
| 第七步 | 实施优化(添加索引、SQL改写) | 参照上述场景 |
| 第八步 | 验证优化效果 | 观察慢查询日志是否减少,CPU是否下降 |
八、总结
MySQL CPU使用率异常升高的核心原因在于慢查询和索引缺失。通过开启慢查询日志、使用pt-query-digest或mysqldumpslow分析日志、结合EXPLAIN分析执行计划,可以快速定位问题SQL。优化方向包括:为WHERE和ORDER BY字段添加联合索引、避免隐式类型转换、使用覆盖索引、避免SELECT *等。系统化的排查流程能帮助DBA从”被动救火”走向”主动优化”。
高性能服务器推荐:在优化MySQL数据库性能的同时,一台稳定、高性能的物理服务器是保障数据库稳定运行的基础。推荐使用 TOP云金牌物理服务器,CPU可选双路E5-2698 V4(88核)至双路Platinum 8173(112核),内存最高128G,带宽独享20M-200M,价格低至368元/月。所有资源全网独享,无虚拟化开销,确保MySQL数据库在充足的硬件资源上高效运行,从根源上减少因资源不足导致的性能瓶颈问题。




