一、背景说明
最近在维护一个线上业务系统时,发现某个核心接口响应时间明显变慢:
-
平均响应时间:1.8s
-
高峰期偶尔超过 3s
-
QPS 上来后,数据库 CPU 明显升高
该接口是一个列表查询接口,调用频率高,已经影响到了用户体验,因此必须进行优化。
二、问题定位:慢在哪里?
1️⃣ 先看接口逻辑
接口主要做了一件事:
根据条件分页查询订单列表
核心 SQL 如下(已脱敏):
SELECT * FROM orders WHERE user_id = ? AND status = ? ORDER BY create_time DESC LIMIT 20 OFFSET 0;
表数据量情况:
-
orders表:约 300 万条数据 -
日增长:几万条
2️⃣ 使用 EXPLAIN 分析执行计划
EXPLAIN SELECT * FROM orders WHERE user_id = 10086 AND status = 1 ORDER BY create_time DESC LIMIT 20 OFFSET 0;
关键输出信息:
-
type: ALL -
rows: 3000000 -
Extra: Using where; Using filesort
👉 全表扫描 + 文件排序
问题已经很明显了。
三、问题根因分析
❌ 主要问题有三个
1. 没有合适的索引
-
user_id -
status -
create_time
虽然单独建过索引,但SQL 用不到
2. 使用了 SELECT *
-
查询了大量无用字段
-
增加 IO 和网络传输成本
3. ORDER BY + LIMIT 在大数据量下性能差
-
Using filesort -
OFFSET 越大,性能越差
四、优化方案设计
✅ 优化目标
-
减少扫描行数
-
让 SQL 命中索引
-
避免 filesort
-
尽量少查字段
五、具体优化步骤
1️⃣ 创建联合索引(最关键一步)
CREATE INDEX idx_user_status_time ON orders (user_id, status, create_time DESC);
索引设计原则:
-
等值查询字段在前
-
排序字段在最后
-
符合最左前缀原则
2️⃣ 避免使用 SELECT *
原 SQL:
SELECT * FROM orders ...
优化后:
SELECT id, order_no, amount, status, create_time FROM orders WHERE user_id = ? AND status = ? ORDER BY create_time DESC LIMIT 20;
3️⃣ 再次 EXPLAIN 验证
EXPLAIN SELECT id, order_no, amount, status, create_time FROM orders WHERE user_id = 10086 AND status = 1 ORDER BY create_time DESC LIMIT 20;
关键变化:
-
type: range -
rows: 几十条 -
Extra: Using index
👉 已经完全走索引
六、优化前后性能对比
| 指标 | 优化前 | 优化后 |
|---|---|---|
| 平均响应时间 | 1.8s | 0.9s |
| 峰值响应时间 | 3s+ | 1.2s |
| 扫描行数 | 300万 | 几十 |
| CPU 占用 | 偏高 | 明显下降 |
整体性能提升约 50% 以上
七、额外优化思路(进阶)
如果数据继续增长,还可以进一步优化:
🔹 1. 使用游标分页(避免 OFFSET)
WHERE create_time < ? ORDER BY create_time DESC LIMIT 20;
🔹 2. 热数据和历史数据分表
🔹 3. 缓存热点数据(Redis)
八、总结
这次 SQL 优化让我再次意识到:
-
慢 SQL ≠ SQL 写得复杂
-
很多性能问题,本质是 索引设计问题
-
EXPLAIN是排查 SQL 性能的第一工具 -
联合索引顺序,决定 SQL 生死
一句话总结:
不是数据库慢,是 SQL 没写对。
九、最后
如果你也遇到过:
-
SQL 查询慢
-
明明有索引却不生效
-
ORDER BY + LIMIT 很卡
- 本文内容由AI辅助生成,经人工审核与编辑后发布。
- 本文部分内容由AI生成,仅供学习与参考,请勿直接引用。
1551

被折叠的 条评论
为什么被折叠?



