华为云RDS for MySQL慢SQL治理实战:从DAS诊断到索引下推的深度优化
接手了一个电商后台系统,数据库用的是华为云RDS for MySQL 8.0(主备版)。最近运营反馈“订单列表页打开要5秒以上”,开发查了半天说SQL没问题。我登录华为云控制台,打开数据管理服务(DAS)的慢SQL分析,发现问题远比想象的复杂。
一、 DAS诊断:慢SQL的“案发现场”
DAS的慢日志统计功能非常直观,按“执行次数”和“平均耗时”排序后,罪魁祸首浮出水面:
sql
SELECT * FROM t_order
WHERE user_id = ? AND status IN (1,2,3)
ORDER BY create_time DESC
LIMIT 20;
这条SQL平均耗时3.2秒,执行频率极高。EXPLAIN一看,走的是user_id的普通索引,但Using filesort(额外排序)和Using where同时出现,说明索引没有覆盖到status和create_time,回表+排序的开销巨大。
二、 优化方案:联合索引 + 索引下推(ICP)
1. 建立覆盖索引
原索引是idx_user_id(user_id)。我们创建一个联合索引,把过滤条件和排序字段都包进去:
sql
ALTER TABLE t_order ADD INDEX idx_user_status_time(user_id, status, create_time);
2. 验证索引下推(Index Condition Pushdown)
MySQL 5.6+默认开启ICP(optimizer_switch中的index_condition_pushdown=on)。建完联合索引后再EXPLAIN,Extra列变成了Using index condition; Using filesort——等等,还是有filesort?
这里踩了个坑:status IN (1,2,3) 是范围条件,导致create_time无法直接利用索引排序。MySQL的B+树在IN多值等值查询后,对后续列的排序是失效的。
3. 改写SQL,利用索引有序性
既然status是固定的几个值,我们把它拆成UNION ALL,每个子查询都能利用(user_id, status, create_time)的有序性,消除filesort:
sql
SELECT * FROM (
SELECT * FROM t_order WHERE user_id = ? AND status = 1 ORDER BY create_time DESC LIMIT 20
UNION ALL
SELECT * FROM t_order WHERE user_id = ? AND status = 2 ORDER BY create_time DESC LIMIT 20
UNION ALL
SELECT * FROM t_order WHERE user_id = ? AND status = 3 ORDER BY create_time DESC LIMIT 20
) t ORDER BY create_time DESC LIMIT 20;
三、 治理效果与DAS二次验证
优化后,DAS慢日志中该SQL的平均耗时从3.2秒降到了0.08秒,EXPLAIN显示Using index(覆盖索引),无filesort。
另外,借助DAS的SQL限流功能,我们对另一条SELECT COUNT(*)的全表扫描SQL(用于后台统计)做了限流,防止它在高峰期拖垮实例。DAS的自动SQL诊断还提示我们有几个表缺少主键,顺手补上了。
四、 总结
华为云RDS + DAS的组合,把慢SQL治理从“盲人摸象”变成了“精准手术”。几点经验:
联合索引的列顺序要遵循“等值在前、范围在后、排序最后”的原则,但IN多值查询会破坏排序,必要时用UNION ALL改写。
DAS的慢日志和自动诊断是排查性能问题的第一入口,比手动开slow_query_log高效得多。
治理完慢SQL后,记得在DAS里做一次SQL审核,防止开发再写出类似的全表扫描。
数据库性能优化没有银弹,但好的工具 + 对执行计划的理解,能让排查效率提升一个数量级。
- 点赞
- 收藏
- 关注作者
评论(0)