广告图片
TOP云-靠谱的企业级公有云服务平台

云服务器、物理服务器、云安全、SSL证书限时3折抢购!

双路E5-2640V4(40核)64G内存480G SSD硬盘30M独享带宽物理机仅需368元;香港铂金云服务器2H/2G/15M仅需19.8元/月;4H/4G/25M仅需29.8元/月,

TOP云-靠谱的企业级公有云服务平台:双路E5-2640V4(40核)64G内存480G SSD硬盘30M独享带宽物理机仅需368元;香港铂金云服务器2H/2G/15M仅需19.8元/月;4H/4G/25M仅需29.8元/月,云服务器、物理服务器、云安全、SSL证书限时3折抢购!点击这里立即抢购! 展开广告

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 filesortUsing 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-digestmysqldumpslow
第六步 对目标SQL执行EXPLAIN EXPLAIN FORMAT=JSON SELECT ...;
第七步 实施优化(添加索引、SQL改写) 参照上述场景
第八步 验证优化效果 观察慢查询日志是否减少,CPU是否下降

八、总结

MySQL CPU使用率异常升高的核心原因在于慢查询和索引缺失。通过开启慢查询日志、使用pt-query-digestmysqldumpslow分析日志、结合EXPLAIN分析执行计划,可以快速定位问题SQL。优化方向包括:为WHERE和ORDER BY字段添加联合索引、避免隐式类型转换、使用覆盖索引、避免SELECT *等。系统化的排查流程能帮助DBA从”被动救火”走向”主动优化”。

高性能服务器推荐:在优化MySQL数据库性能的同时,一台稳定、高性能的物理服务器是保障数据库稳定运行的基础。推荐使用 TOP云金牌物理服务器,CPU可选双路E5-2698 V4(88核)至双路Platinum 8173(112核),内存最高128G,带宽独享20M-200M,价格低至368元/月。所有资源全网独享,无虚拟化开销,确保MySQL数据库在充足的硬件资源上高效运行,从根源上减少因资源不足导致的性能瓶颈问题。

阿, 信