一次真实的接口性能优化:从 2s 到 80ms 的排查过程
很多性能优化文章都会讲方法论,但在实际工作中,真正有价值的是:
👉 你是怎么一步步定位问题的
这篇文章记录一个真实场景:
一个接口从平均 2s 响应时间,优化到 80ms 的全过程。
一、问题背景
某业务接口 /getUserList,用于分页查询用户列表。
初期数据量较小时一切正常,但上线 3 个月后:
- 平均响应时间:2s+
- 高峰期:偶尔超时
- 数据量:约 50 万
二、第一步:确认瓶颈位置
先通过监控工具(如 Prometheus)查看:
- CPU:正常
- 内存:正常
- QPS:不高
👉 初步判断:不是系统资源问题
然后加埋点日志,拆解耗时:
接口总耗时:2100ms
- 数据库查询:1800ms
- 数据处理:200ms
- 其他:100ms
👉 结论:问题在数据库
三、第二步:分析 SQL
核心 SQL:
SELECT * FROM user
WHERE status = 1
ORDER BY create_time DESC
LIMIT 0, 20;
看起来很简单,但问题在于:
👉 没有合适索引
使用 EXPLAIN 分析后发现:
- type: ALL(全表扫描)
- rows: 500000+
四、第一次优化:加索引
增加复合索引:
CREATE INDEX idx_status_time
ON user(status, create_time);
优化后:
- 查询时间:1800ms → 400ms
👉 有提升,但还不够
五、第三步:发现隐藏问题(分页陷阱)
当分页页数变大时:
LIMIT 100000, 20;
MySQL 实际会:
👉 先扫描 100020 条,再丢弃前 100000 条
这就是经典的深分页问题。
六、第二次优化:改写分页方式
改为“基于游标”的分页:
SELECT * FROM user
WHERE status = 1
AND create_time < last_time
ORDER BY create_time DESC
LIMIT 20;
👉 优化后:
- 查询时间:400ms → 120ms
七、第四步:缓存优化
观察业务发现:
👉 用户列表数据变化频率不高
于是引入 Redis 缓存:
- 热门分页直接走缓存
- 设置合理过期时间
👉 优化后:
- 接口整体:120ms → 80ms
八、最终结果对比
| 阶段 | 响应时间 |
|---|---|
| 初始 | 2100ms |
| 加索引 | 400ms |
| 优化分页 | 120ms |
| 加缓存 | 80ms |
九、几个关键经验总结
1️⃣ 不要一上来就“优化代码”
先定位瓶颈在哪一层(数据库 / 代码 / 网络)
2️⃣ SQL 永远是性能核心
- 索引是否合理
- 是否存在全表扫描
- 是否有深分页
👉 这些问题远比代码优化影响更大
3️⃣ 分页是高频坑
尤其是:
LIMIT offset, size
当 offset 很大时,性能会急剧下降。
4️⃣ 缓存不是万能,但很关键
适合场景:
- 读多写少
- 热点数据明显
5️⃣ 优化是“逐步逼近”的过程
很少有“一次到位”的优化,通常是:
👉 定位 → 优化一点 → 再定位 → 再优化
十、写在最后
很多人觉得性能优化很难,其实本质就三件事:
- 找到慢的地方
- 理解为什么慢
- 用合适的方法解决
真正拉开差距的,不是你会多少“技巧”,
而是你有没有完整做过一轮优化闭环。
如果你有类似的慢接口(SQL 或代码),可以贴出来,我可以帮你一起分析一下问题在哪。