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

网站设计哪家便宜seo网站做推广公司

网站设计哪家便宜,seo网站做推广公司,wordpress文档结构,凡科网站模板下载作为一名全职Java开发实习生,我始终坚信:“慢接口”不是业务复杂的问题,而是代码设计与数据访问方式的失衡。 最近,我在优化一个生产环境的“排班计划看板接口”时,经历了一场从 2分钟 → 200ms 的性能跃迁。整个过程没…

作为一名全职Java开发实习生,我始终坚信:“慢接口”不是业务复杂的问题,而是代码设计与数据访问方式的失衡。 最近,我在优化一个生产环境的“排班计划看板接口”时,经历了一场从 2分钟 → 200ms 的性能跃迁。整个过程没有引入任何中间件或分布式架构,靠的是对业务逻辑的深入理解、SQL优化、批量查询思维和代码重构。

今天,我就带大家复盘这次优化全过程,分享我在熟悉与不熟悉代码区域中如何精准定位瓶颈、果断重构、实现质的飞跃的经验。


一、问题背景:一个“慢得离谱”的看板接口

我们有一个用于生产管理的“排班计划看板”,前端需要展示如下信息:

  • 排班基础信息(班次、产线、计划数量等)
  • 质检员姓名
  • 当前工序序号
  • 反馈备注与缺陷总数
  • 首检/末检状态(待检/合格/不合格)

原始接口在数据量仅150条时,响应时间竟高达 120秒以上,用户反馈“每次打开都像在等一场电影加载”。这显然不可接受。


二、第一阶段:从“熟悉区”入手,先稳住基本盘

我首先从自己熟悉的模块开始优化,目标是先解决最明显的性能问题

1. 精简返回字段,减少数据传输开销

检查接口返回的 ZhhPlanShifts 实体类,发现包含了大量前端根本不需要的字段,如 createByupdateTimeremark 等。这些字段不仅增加了数据库IO,还增大了网络传输体积。

优化措施:

  • 在 resultMap 中只 SELECT 前端需要的字段。
  • 使用 覆盖索引(Covering Index),让查询完全走索引,避免回表。
-- 为 zhh_plan_shifts 表添加覆盖索引
CREATE INDEX idx_covering ON zhh_plan_shifts (create_time, qc_id, route_id, line_name, line_id);

这样,数据库可以直接从索引中获取所有数据,无需访问主表。

2. 批量查询替代逐条查询(N+1问题终结)

原始代码中存在典型的 N+1 查询问题

// 问题代码:每条记录都查一次数据库
for (Long planShiftId : planShiftIds) {List<ProFeedback> feedbacks = proFeedbackMapper.selectProFeedbackByPlanShiftsId(planShiftId);feedbackMap.put(planShiftId, feedbacks);
}

150条记录 → 150次数据库查询,网络延迟叠加,性能雪崩。

优化措施:

  • 新增批量查询方法:
List<ProFeedback> selectProFeedbackByPlanShiftsIds(@Param("planShiftsIds") List<Long> planShiftsIds);
  • 一次查询获取所有反馈数据,再用 Java Stream 分组:
List<ProFeedback> allFeedbacks = proFeedbackMapper.selectProFeedbackByPlanShiftsIds(planShiftIds);
Map<Long, List<ProFeedback>> feedbackMap = allFeedbacks.stream().collect(Collectors.groupingBy(ProFeedback::getPlanShiftsId));

效果:数据库查询次数从 150 次 → 1 次,性能提升立竿见影。


三、第二阶段:深入“陌生代码区”,重构逻辑,精准减负

当熟悉的部分优化完毕后,我发现接口仍耗时约 30 秒。这时,我决定深入之前“不敢动”的代码区域——那些由前同事编写、逻辑复杂、注释稀少的模块。

1. 逆向分析:从“前端需要什么”反推代码逻辑

我没有直接阅读代码,而是采取了更高效的方式:

  • 打开浏览器开发者工具,查看前端实际渲染了哪些字段。
  • 发现:qcName(质检员姓名)、serialNumber(工序序号)虽然在实体类中,但前端并未使用

但代码中却为此执行了两次额外查询:

// 查询质检员姓名(前端不用!)
List<SysUser> users = userMapper.selectUsersByIds(qcIds);// 逐条查询工序序号(性能极差)
Integer serialNumber = proRouteProcessMapper.selectByOrderNum(ps.getRouteId(), ps.getLineName());

果断决策:删除这两段冗余代码!

📌 经验分享:不要被“代码存在即合理”束缚。如果字段前端不用,就大胆移除,避免“为了显示而查询”的陷阱。

2. 重构 IPQC 查询:批量参数化查询

原代码对 qc_ipqc 表的查询虽已批量,但方式不够优雅:

List<Map<String, Object>> queryParams = new ArrayList<>();
for (ZhhPlanShifts item : zhhPlanShiftsList) {Map<String, Object> param = new HashMap<>();param.put("planShiftsId", item.getId());param.put("lineId", item.getLineId());queryParams.add(param);
}

优化建议:改用 IN 条件或更高效的批量查询方式(如 WHERE (plan_shifts_id, line_id) IN ((1,101), (2,102))),但受限于 MyBatis 支持,当前方式已可接受。


四、代码对比:优化前 vs 优化后

优化前(耗时 > 120s)

@Override
public List<ZhhPlanShifts> selectZhhPlanShiftsListToKanban(ZhhPlanShifts zhhPlanShifts) {List<ZhhPlanShifts> zhhPlanShiftsList = zhhPlanShiftsMapper.selectZhhPlanShiftsList(zhhPlanShifts);// ❌ 多余的质检员查询Set<Long> qcIds = zhhPlanShiftsList.stream().map(ZhhPlanShifts::getQcId).filter(Objects::nonNull).collect(Collectors.toSet());Map<Long, String> userNickNameMap = new HashMap<>();if (!qcIds.isEmpty()) {List<SysUser> users = userMapper.selectUsersByIds(new ArrayList<>(qcIds));userNickNameMap = users.stream().collect(Collectors.toMap(SysUser::getUserId, SysUser::getNickName));}// ❌ 逐条查询工序序号(N+1)Map<String, Integer> serialNumberMap = new HashMap<>();for (ZhhPlanShifts ps : zhhPlanShiftsList) {Integer serialNumber = proRouteProcessMapper.selectByOrderNum(ps.getRouteId(), ps.getLineName());serialNumberMap.put(ps.getRouteId() + "_" + ps.getLineName(), serialNumber);}// ❌ 逐条查询反馈数据(N+1)for (Long planShiftId : planShiftIds) {List<ProFeedback> feedbacks = proFeedbackMapper.selectProFeedbackByPlanShiftsId(planShiftId);}// ... 其他处理
}

优化后(耗时 ≈ 200ms)

@Override
public List<ZhhPlanShifts> selectZhhPlanShiftsListToKanban(ZhhPlanShifts zhhPlanShifts) {// ✅ 覆盖索引 + 精简字段List<ZhhPlanShifts> zhhPlanShiftsList = zhhPlanShiftsMapper.selectZhhPlanShiftsList(zhhPlanShifts);if (zhhPlanShiftsList.isEmpty()) return zhhPlanShiftsList;// ✅ 批量查询反馈数据Set<Long> planShiftIds = zhhPlanShiftsList.stream().map(ZhhPlanShifts::getId).filter(Objects::nonNull).collect(Collectors.toSet());Map<Long, List<ProFeedback>> feedbackMap = new HashMap<>();if (!planShiftIds.isEmpty()) {List<ProFeedback> allFeedbacks = proFeedbackMapper.selectProFeedbackByPlanShiftsIds(planShiftIds);feedbackMap = allFeedbacks.stream().collect(Collectors.groupingBy(ProFeedback::getPlanShiftsId));}// ✅ 单次遍历填充缺陷数for (ZhhPlanShifts planShifts : zhhPlanShiftsList) {List<ProFeedback> proFeedbacks = feedbackMap.getOrDefault(planShifts.getId(), Collections.emptyList());long totalDefectCount = proFeedbacks.stream().mapToLong(pf -> (pf.getQuantityUnquanlified() != null ? pf.getQuantityUnquanlified() : 0) +(pf.getAttr3() != null ? pf.getAttr3() : 0) +(pf.getAttr4() != null ? pf.getAttr4() : 0) +(pf.getQuantityTestFailed() != null ? pf.getQuantityTestFailed() : 0)).sum();planShifts.setDefectCount(totalDefectCount);}// ✅ 批量查询 IPQC 状态List<Map<String, Object>> queryParams = buildQueryParams(zhhPlanShiftsList);List<QcIpqc> allQcIpqcs = qcIpqcMapper.selectQcIpqcListByBatch(queryParams);Map<Long, List<QcIpqc>> qcIpqcMap = allQcIpqcs.stream().collect(Collectors.groupingBy(QcIpqc::getPlanShiftsId));// ✅ 填充首检/末检状态for (ZhhPlanShifts item : zhhPlanShiftsList) {List<QcIpqc> qcIpqcs = qcIpqcMap.getOrDefault(item.getId(), Collections.emptyList());item.setFirstCheckStatus("未检查");item.setFinalCheckStatus("未检查");for (QcIpqc ipqc : qcIpqcs) {if ("FIRST".equals(ipqc.getIpqcType())) {item.setFirstCheckStatus(convertStatus(ipqc.getStatus()));} else if ("FINAL".equals(ipqc.getIpqcType())) {item.setFinalCheckStatus(convertStatus(ipqc.getStatus()));}}}return zhhPlanShiftsList;
}

五、总结:性能优化的四大心法

  1. 从熟悉区入手,建立信心
    先优化自己熟悉的模块,快速见效,增强继续优化的动力。

  2. 以终为始:前端需要什么,就查什么
    不要“为了查而查”,避免传输和计算无用数据。

  3. 终结 N+1 查询
    任何循环内查数据库的代码都是性能杀手,必须重构为批量查询。

  4. 善用索引,尤其是覆盖索引
    让查询尽可能走索引,减少磁盘IO和回表操作。


六、后续优化方向

  • SQL 层聚合:将 defectCount 计算下推到 SQL 层,使用 SUM() 和 GROUP BY,进一步减少 Java 层计算。
  • 本地缓存:对 sys_userpro_route_process 等静态数据做本地缓存(如 Caffeine)。
  • 异步加载:将非核心数据(如历史反馈)异步加载,提升首屏速度。

性能优化不是一蹴而就,而是一场持续的“代码瘦身”与“数据精炼”之旅。 只要你愿意深入每一行代码,敢于质疑“为什么”,就能让系统从“龟速”变为“闪电”。

我是一个热爱性能优化的Java开发者。关注我,带你从实战中提升代码质量与系统性能。

http://www.dtcms.com/a/600784.html

相关文章:

  • 用于感知图像超分辨率的自编码监督(易于理解版本)
  • 地图可视化实践录:空间分析库Turf.js的学习
  • 长沙制作网站公司哪家好广州seo推广营销
  • 11、prometheus-PromQL-5-聚合计算函数
  • (114页PPT)上海x友集团管理咨询及IT规划项目第一期报告管理诊断分析咨询报告(附下载方式)
  • C语言编译器 Visual Studio:实现高效编程与调试环境优化
  • 王树森深度强化学习 DRL(六)连续控制 DDPG + 随机策略
  • 【SatWetCH4 第一期】全球湿地甲烷排放通量估算过程模型 SatWetCH4 介绍
  • Opencv(十一) : 图像缩放
  • 开源 Objective-C IOS 应用开发(四)Xcode工程文件结构
  • 儿童网站 源码html5网站开发教学
  • 编译类语言的特点与应用
  • Python 数组使用方法总结
  • 网站风格变化免费logo在线制作头像
  • 第三章深度解析:智能体“大脑”的底层逻辑——大语言模型技术基石全拆解
  • 100个云计算基础知识
  • 对比 DeepSeek(MLA)、Qwen 和 Llama 系列大模型在 Attention 架构/算法层面的核心设计及理解它们的本质区别。
  • 【C++】List容器模拟实现(超详细)
  • 湖南火电建设有限公司网站龙采哈尔滨建站公司
  • 【PHP反序列化】css夺旗赛
  • ServletLess架构简介
  • 安卓C语言编译器的选择与使用技巧 | 优化C语言编程体验,提升开发效率
  • (三)自然语言处理笔记——Transformer
  • iOS性能分析工具,有UI卡顿、app启动、内存、webview等性能优化解析
  • 电商网站建设 数商云招商码头无忧查询系统
  • 开源 Objective-C IOS 应用开发(三)第一个iPhone的APP
  • (11)(2.2.2) BLHeli32,AM32, and BLHeli_S ESCs(二)
  • Google Chrome v142.0.7444.135 便携增强版
  • [Windows] PDF文件浏览OCR工具1.0
  • 2025人形机器人产业链全景分析报告:核心技术与市场趋势|附130+份报告PDF、数据、可视化模板汇总下载