华为云 RDS for MySQL 慢 SQL 实战:从慢日志到 EXPLAIN 的完整优化路径
数据库突然变慢,十有八九是某条 SQL 在悄悄拖后腿。慢查询不解决,加机器也只是延缓崩溃。
一、慢,通常不是无缘无故
RDS 实例 CPU 飙高、连接数打满、接口超时,很多人的第一反应是"配置不够",于是升规格、加只读。但如果根因是一条没走索引的 SQL,加再多资源也只是把雪崩时间往后推一点。性能排查的正确顺序永远是:先定位慢 SQL,再谈优化。
二、第一步:把慢 SQL 捞出来
华为云 RDS for MySQL 的慢日志会记录超过阈值的语句,阈值由参数 long_query_time 控制(单位秒)。可以在控制台的"慢日志"页签按时间、耗时分位排序查看,同时还能看到执行次数、扫描行数等统计。
关键是别只盯着"最慢的那一条",而要结合执行次数 × 单次耗时判断影响面:一条 2 秒但每秒执行 100 次的 SQL,远比一条 10 秒却一天只跑一次的 SQL 更值得优先处理。
三、第二步:用 EXPLAIN 看清执行计划
拿到可疑 SQL 后,第一件事是 EXPLAIN:
EXPLAIN SELECT id, name
FROM orders
WHERE user_id = 10086 AND status = 1
ORDER BY created_at DESC
LIMIT 20;
重点看几个字段:
type:出现ALL(全表扫描)基本就是坏味道,理想是ref/range/index;key:实际用到的索引,为NULL说明压根没走索引;rows:预估扫描行数,越大越要警惕;Extra:出现Using filesort、Using temporary往往意味着额外的排序或临时表开销。
四、第三步:对症下药
最常见的病因是缺索引。 上面的查询,建一个联合索引就能同时覆盖过滤与排序:
ALTER TABLE orders ADD INDEX idx_user_status_time (user_id, status, created_at);
这样既命中 user_id + status 的过滤条件,又利用 created_at 消除了 filesort。注意联合索引要遵守最左前缀:(user_id, status, created_at) 能服务 user_id、user_id+status、user_id+status+created_at 三种查询,但单独按 status 查就用不上。
第二常见的是索引失效,典型场景包括:在索引列上套函数(如 WHERE DATE(created_at) = '2026-01-01')、隐式类型转换(字符串列传了数字)、以 % 开头的模糊匹配,以及 OR 混用导致优化器放弃索引。
深分页也是重灾区。LIMIT 1000000, 20 会先扫过一百万行再丢弃,改用延迟关联或基于游标的 WHERE id > last_id 能显著改善。
五、实战避坑清单
- 优化前先看执行次数:高频的小慢查询,对整体影响往往大于低频的大慢查询。
- 索引不是越多越好:每个索引都会增加写入成本与存储占用,优先做联合索引,避免重复冗余。
- 别在高峰期改表:大表加索引可能长时间占用 IO,尽量使用 Online DDL 或在业务低峰执行。
- 变更先在只读实例验证:用真实数据跑过 EXPLAIN 和压测,确认效果后再上生产。
- 警惕隐式转换:字段类型与传参类型不一致是索引失效的高发区,从接口层就要统一类型。
- 慢日志阈值按业务调:
long_query_time设得太小会淹没真正的问题,设得太大又会漏掉隐患,建议先设成 1 秒观察一段时间再逐步收紧。
六、小结
慢 SQL 优化是一条固定的流水线:慢日志定位 → EXPLAIN 分析 → 索引与写法优化 → 验证上线。绝大多数"数据库慢"的问题,都能在这几步里找到答案。与其盲目升配,不如先把那条拖后腿的 SQL 揪出来。
- 点赞
- 收藏
- 关注作者
评论(0)