当前位置: 首页 > news >正文

我是如何把一个接口的响应时间从 2s 优化到 50ms 的

背景

上周线上监控报警,有一个用户列表查询接口的平均响应时间达到了 2.3 秒,高峰期甚至超过 5 秒,严重影响了用户体验。

这个接口是我一年前写的,当时数据量小,没觉得有什么问题。现在用户表已经有 500 多万条数据了,性能问题就暴露出来了。

今天我把整个优化过程记录下来,从问题定位到最终优化完成,一步步带大家看如何把一个慢接口优化到 50ms 以内。

第一步:定位问题

首先用 Postman 测试了一下接口,确实很慢。然后我打开了 MySQL 的慢查询日志,找到了对应的 SQL 语句:

sql

SELECT u.id, u.username, u.email, u.phone, r.role_name, d.dept_name FROM user u LEFT JOIN role r ON u.role_id = r.id LEFT JOIN dept d ON u.dept_id = d.id WHERE u.status = 1 ORDER BY u.create_time DESC LIMIT 10 OFFSET 100000;

执行时间:2.1 秒。

问题 1:深度分页导致的性能问题

LIMIT 10 OFFSET 100000这种写法会让 MySQL 扫描 100010 行数据,然后丢弃前 100000 行,只返回最后 10 行。当偏移量很大时,性能会急剧下降。

优化方案:使用游标分页

sql

-- 优化前 SELECT * FROM user WHERE status = 1 ORDER BY id DESC LIMIT 10 OFFSET 100000; -- 优化后 SELECT * FROM user WHERE status = 1 AND id < 100000 ORDER BY id DESC LIMIT 10;

这样 MySQL 只需要扫描 10 行数据,执行时间从 2.1 秒降到了 0.01 秒。

问题 2:没有合适的索引

查看了一下表结构,发现statuscreate_time和关联字段role_iddept_id都没有建索引。

优化方案:添加合适的索引

sql

-- 给查询条件和排序字段建联合索引 CREATE INDEX idx_user_status_create_time ON user(status, create_time DESC); -- 给关联字段建索引 CREATE INDEX idx_user_role_id ON user(role_id); CREATE INDEX idx_user_dept_id ON user(dept_id);

添加索引后,查询时间降到了 0.3 秒。

问题 3:不必要的关联查询

查看代码发现,这个接口返回的角色名称和部门名称其实很少变化,而且大部分用户都属于同一个部门和角色。

优化方案:使用缓存

java

运行

// 原来的代码 List<UserVO> userList = userMapper.selectUserList(query); for (UserVO user : userList) { Role role = roleMapper.selectById(user.getRoleId()); user.setRoleName(role.getName()); Dept dept = deptMapper.selectById(user.getDeptId()); user.setDeptName(dept.getName()); } // 优化后的代码 // 先把所有角色和部门加载到缓存中 Map<Long, String> roleMap = roleMapper.selectAll().stream() .collect(Collectors.toMap(Role::getId, Role::getName)); Map<Long, String> deptMap = deptMapper.selectAll().stream() .collect(Collectors.toMap(Dept::getId, Dept::getName)); // 然后在循环中直接从缓存中获取 for (UserVO user : userList) { user.setRoleName(roleMap.get(user.getRoleId())); user.setDeptName(deptMap.get(user.getDeptId())); }

这样就把原来的 N+1 次查询变成了 3 次查询,接口响应时间降到了 0.1 秒。

问题 4:返回了不必要的字段

查看接口返回结果,发现返回了很多不需要的字段,比如passwordsaltupdate_time等。

优化方案:只返回需要的字段

java

运行

// 原来的代码 List<User> userList = userMapper.selectList(queryWrapper); // 优化后的代码 List<UserVO> userList = userMapper.selectUserList(query);

在 Mapper 中只查询需要的字段,减少数据传输量。

最终优化结果

经过以上几步优化,接口的平均响应时间从 2.3 秒降到了 45ms,高峰期也不超过 100ms,完美解决了性能问题。

总结

接口优化是一个系统性的工作,需要从多个方面入手:

  1. 先定位慢查询,优化 SQL 语句
  2. 添加合适的索引
  3. 避免 N+1 查询,使用缓存
  4. 只返回需要的字段
  5. 考虑使用 Redis 缓存热点数据

记住:过早优化是万恶之源,但不优化也是万恶之源。在开发初期就要考虑到性能问题,避免后期踩大坑。

http://www.jsqmd.com/news/893717/

相关文章:

  • 毫米波雷达:智能驾驶的“全天候之眼”,一文读懂原理、应用与未来
  • 保姆级教程:在Ubuntu 22.04上为你的RDMA应用创建第一个Protection Domain (PD)
  • 2026年PDF转Word免费推荐:这5款工具真正无损还原格式 - 时时资讯
  • 2026数据中台选型指南
  • 市面上好用的命理有哪些?这几点挑错等于白花钱
  • 2026年 徐州/江苏柜体厂家推荐排行榜:多层无漆柜体、实木烤漆柜体、橱柜衣柜阳台柜柜体源头实力品牌精选 - 品牌企业推荐师(官方)
  • 2026 实测!视频号视频无水印下载方法
  • 2026年5月有实力的快装阳光房配件厂家排行推荐榜,快装阳光房配件、阳光房连接件、阳光房角码厂家选择指南 - 海棠依旧大
  • ue打包常见问题(持续更新中……)
  • 【DevOps】CI/CD最佳实践:从自动化构建到持续部署
  • 2026年精选AI论文软件指南(实测甄选版)
  • 大语言模型处理大规模代码的认知误区与合理实践
  • 字符串算法进阶总结 | 滑动窗口、回文与匹配
  • 使用 Taotoken 为你的 AI 应用提供稳定可靠的后端模型服务
  • 宜宾本地及全国搬家品牌排行:宜宾喜来乐搬家、宜宾小型搬家、宜宾工厂搬迁、宜宾店铺搬迁、宜宾异地搬家、宜宾搬迁厂房选择指南 - 优质品牌商家
  • c#基础知识合集11 数组的属性 数组的高级函数 lambda表达式
  • 2026可靠水质检测设备推荐榜:水质检测哪里检测/水质检测第三方机构公司/水质监测仪/第三方水质检测公司/职业卫生检测机构/选择指南 - 优质品牌商家
  • ESP32-CAM + YOLOv5实战:手把手教你搭建低成本智能监控(附Python服务端完整代码)
  • IDEA安装、使用、配置
  • IT68353:DP 1.4 + HDMI 2.0 + USB-C 三合一转 HDMI 2.0 单芯片KVM切换方案
  • 新人报道贴
  • Windows 10开机自动隐藏指定软件图标:手把手制作你的专属“托盘清洁”脚本
  • 2026年无尘车间/净化工程精选推荐榜:食品电子医疗洁净厂房源头厂家与实验室无菌室优质品牌深度解析 - 企业推荐官【官方】
  • 阿里 Qwen3.7-Max 编程能力飙升至全球第二!Code Arena 盲测 1541 分,超越 Claude Opus 4.6
  • 为什么需要向量库? 向量化、向量匹配与检索原理解析
  • 2026年5月正规的心理测评系统公司怎么选厂家推荐榜,心理测评软件、心理测评一体机、云心理测评平台厂家选择指南 - 海棠依旧大
  • 2026年5月靠谱的深圳软件开发外包公司找哪家厂家推荐榜:APP开发、小程序开发、物联网系统开发厂家选择指南 - 海棠依旧大
  • 2026夏季纯棉文化衫新趋势:定制你的个性清凉,穿出专属团队风采
  • 个人微信机器人防封指南:如何给 AI 助理加上敏感词过滤
  • 为什么 Chunk(分块)策略,会决定 RAG 的效果上限?