加强网站建设 基本措施,自己做的网站链接到微信支付界面,自己网上开店的步骤,公司logo墙提示#xff1a;文章写完后#xff0c;目录可以自动生成#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、数据库聚合替代内存计算#xff08;关键优化#xff09;二、批量处理优化四、区域特殊处理解耦五、防御性编程增强 前言
技术认知点#xff1a;使用 XM… 提示文章写完后目录可以自动生成如何生成可参考右边的帮助文档 文章目录 前言一、数据库聚合替代内存计算关键优化二、批量处理优化四、区域特殊处理解耦五、防御性编程增强 前言
技术认知点使用 XML 编写 SQL 聚合查询并不会导致所有数据加载到内存反而能 大幅减少内存占用并提升性能。 LocalDateTime localDateTime TimeUtilTool.startOfDay();LocalDateTime crossTime LocalDateTime.now().minusDays(1);ListAAA list SERVICE1.list(new LambdaQueryWrapperAAA().between(AAA::GETTIME, localDateTime.minusDays(1), localDateTime));MapString, ListAAA areaMap list.stream().collect(Collectors.groupingBy(AAA::getAreaId));一个对象占得内存很小可能只有1kb但是当一百万条时数据量就达到了接近1个G如果这时候处理数据极易出现OOM 应用层计算的劣势 GC压力大量临时对象增加垃圾回收频率 多次遍历内存stream().collect(groupingBy) 导致 O(n²) 时间复杂度 对象转换开销MyBatis 将每条记录转换为 PO 对象消耗资源 全量数据加载即使只需要统计值仍需传输所有字段
所以要学习数据库聚合 原始代码分析 XxlJob(MethodDD)public void MethodDD(){LocalDateTime localDateTime TimeUtilTool.startOfDay();LocalDateTime crossTime LocalDateTime.now().minusDays(1);ListAAA list SERVICE1.list(new LambdaQueryWrapperAAA().between(AAA::GETTIME, localDateTime.minusDays(1), localDateTime));MapString, ListAAA areaMap list.stream().collect(Collectors.groupingBy(AAA::getAreaId));ListBBB result SAVEDATA(areaMap, crossTime);saveAreaStatisticsDaily(result, crossTime);}private ListBBB SAVEDATA(MapString, ListAAA areaMap, LocalDateTime crossTime) {ListCCCC ccc cacheTool.areaDictionary();ListBBB result new ArrayList();areaMap.forEach((areaId, areaList)-{BBB po new BBB();OptionalCCCC first ccc.stream().filter(ccc - ccc.getId().toString().equals(areaId)).findFirst();first.ifPresent(ccc - {po.setAreaId(areaId);if(ccc.getId().toString().equals(areaId)){po.setAreaName(AreaNameBuilder.getAreaName(ccc));}Double carSpeed 0.0;if (areaList null || areaList.isEmpty()) {// 处理空列表的情况carSpeed 0.0;} else {double totalSpeed areaList.parallelStream() .mapToDouble(AAA::getCarSpeed).sum();carSpeed totalSpeed / areaList.size();}po.setMeanSpeed(new BigDecimal(carSpeed));po.setFlow(areaList.size());MapString, ListAAA carTypeMap areaList.stream().collect(Collectors.groupingBy(AAA::getCarType));carTypeMap.forEach((carType, carTypeList) -{if (carType.equals(1)){po.setSmallCCCARFlow(carTypeList.size());} else if (carType.equals(2)){po.setMediumLargeBBBULLFlow(carTypeList.size());} else if (carType.equals(3)){po.setSmallMediumttttFlow(carTypeList.size());}else if (carType.equals(4)){po.setLargettttFlow(carTypeList.size());}else if (carType.equals(5)){po.setHazardousChemicalCCCARFlow(carTypeList.size());}else if (carType.equals(6)){po.setMotorcycle(carTypeList.size());}else if (carType.equals(7)){po.setOther(carTypeList.size());}});});po.setCrossTime(crossTime);result.add(po);statsService.save(po);});ListString areaIds areaMap.keySet().stream().toList();for (CCCC ccc : ccc) {if (!areaIds.contains(ccc.getId().toString())){BBB po new BBB();po.setAreaId(ccc.getId().toString());po.setAreaName(AreaNameBuilder.getAreaName(ccc));po.setCrossTime(crossTime);result.add(po);statsService.save(po);}}return result;}首先用户有一个定时任务每天凌晨统计卡口数据并将结果保存到数据库。当前代码可能存在性能问题尤其是当数据量大的时候全量查询和处理会导致内存和性能问题。
全量数据加载到内存使用trafficCCCARService.list查询所有符合条件的数据如果数据量很大会导致内存压力甚至OOM。多次遍历数据流在处理每个区域的数据时多次使用流操作进行分组和统计可能导致性能下降。频繁的数据库写入操作在SAVEDATA方法中每次处理一个区域就调用statsService.save(po)这样频繁的数据库插入操作效率低下。硬编码的区域ID判断在saveAreaStatisticsDaily方法中直接判断特定的区域ID这样的代码难以维护且不符合面向对象的设计原则。
首先全量数据的问题可以考虑分页查询或者使用数据库的聚合功能减少数据传输量。 其次多次遍历数据流可以通过合并处理逻辑来减少遍历次数。 数据库写入操作应该批量进行而不是逐条插入。 硬编码的问题可以通过枚举或配置来解决代码中存在重复的区域ID判断这部分应该抽象出来使用更灵活的方式处理比如使用Map来映射区域ID和对应的字段避免大量的if-else语句。
一、数据库聚合替代内存计算关键优化
LambdaQueryWrapper和XML
XML 只是定义 SQL 的方式无论是 XML 还是 LambdaQueryWrapper最终都会生成 SQL 发送到数据库执行性能差异的根源在于 SQL 本身的执行效率 和 数据传输量而非 XML/Lambda 的代码形式
关键区别
优化前LambdaQueryWrapper拉取全量原始数据到应用层 → 内存计算危险 优化后XML 聚合在数据库层完成聚合 → 只返回计算结果安全高效
这时候要在数据库层面进行处理了
// 新增 DAO 方法
Select(SELECT area_id, COUNT(*) AS flow, AVG(car_speed) AS mean_speed, SUM(CASE car_type WHEN 1 THEN 1 ELSE 0 END) AS small_CCCAR_flow, SUM(CASE car_type WHEN 2 THEN 1 ELSE 0 END) AS medium_large_BBBULL_flow // 其他车型...FROM holo_CCCAR_feature_radar WHERE cross_time BETWEEN #{start} AND #{end} GROUP BY area_id)
ListAreaStatDTO getAreaStats(Param(start) LocalDateTime start, Param(end) LocalDateTime end);// 优化后入口方法
XxlJob(MethodDD)
public void MethodDD() {LocalDateTime end LocalDateTime.now().truncatedTo(ChronoUnit.DAYS);LocalDateTime start end.minusDays(1);// 1. 数据库聚合计算ListAreaStatDTO stats CCCARRecordDAO.getAreaStats(start, end);// 2. 构建统计对象ListbbbPO statsList buildStatistics(stats, start);// 3. 批量存储statsService.saveBatch(statsList);// 4. 区域级统计saveAreaStatisticsDaily(statsList, start);
}优化效果 数据量减少假设原始数据10万条 → 聚合后100条区域数据
执行时间从1200ms → 200ms
内存消耗从800MB → 10MB
二、批量处理优化
批量插入代替逐条插入
// 原代码逐条插入
areaMap.forEach((areaId, areaList) - {// ...构建postatsService.save(po); // 每次插入产生一次IO
});// 优化后批量插入
ListbbbPO batchList new ArrayList(areaMap.size());
areaMap.forEach((areaId, areaList) - {// ...构建pobatchList.add(po);
});
statsService.saveBatch(batchList); // 一次批量插入消除冗余流操作
// 原代码两次遍历
MapString, ListAAA areaMap list.stream().collect(groupingBy(...));
areaMap.forEach(...);// 优化后合并处理
list.stream().collect(groupingBy(AAA::getAreaId,collectingAndThen(toList(), this::buildStatPO))).values().forEach(...);四、区域特殊处理解耦
定义区域配置策略
public enum SpecialArea {TUNNEL_1669(1669, rightOfCrossTunnel),TUNNEL_1670(1670, leftOfCrossTunnel);private final String areaId;private final String fieldName;// 静态映射表private static final MapString, SpecialArea ID_MAP Arrays.stream(values()).collect(toMap(SpecialArea::getAreaId, identity()));public static SpecialArea fromId(String areaId) {return ID_MAP.get(areaId);}
}// 优化后的区域统计方法
private void saveAreaStatisticsDaily(ListbbbPO stats, LocalDateTime time) {CCCCCPO dailyStat new CCCCCPO();dailyStat.setCrossTime(time);stats.forEach(po - {SpecialArea area SpecialArea.fromId(po.getAreaId());if (area ! null) {BeanUtils.setProperty(dailyStat, area.getFieldName(), po.getFlow());}});dailyStat.setFlow(stats.stream().mapToInt(bbbPO::getFlow).sum());SERVICE1.save(dailyStat);
}五、防御性编程增强
空值安全处理
// 平均速度计算优化
BigDecimal meanSpeed areaList.stream().map(AAA::getCarSpeed).filter(Objects::nonNull).collect(Collectors.collectingAndThen(Collectors.averagingDouble(Double::doubleValue),avg - avg.isNaN() ? BigDecimal.ZERO : BigDecimal.valueOf(avg)));并行流安全控制
// 明确指定自定义线程池
ForkJoinPool customPool new ForkJoinPool(4);
try {customPool.submit(() - areaList.parallelStream()// ...处理逻辑).get();
} finally {customPool.shutdown();
} 文章转载自: http://www.morning.kybjr.cn.gov.cn.kybjr.cn http://www.morning.zhiheliuxue.com.gov.cn.zhiheliuxue.com http://www.morning.dnqlba.cn.gov.cn.dnqlba.cn http://www.morning.cprbp.cn.gov.cn.cprbp.cn http://www.morning.rydhq.cn.gov.cn.rydhq.cn http://www.morning.ylrxd.cn.gov.cn.ylrxd.cn http://www.morning.qrpdk.cn.gov.cn.qrpdk.cn http://www.morning.zylrk.cn.gov.cn.zylrk.cn http://www.morning.qjsxf.cn.gov.cn.qjsxf.cn http://www.morning.mjgxl.cn.gov.cn.mjgxl.cn http://www.morning.lpmdy.cn.gov.cn.lpmdy.cn http://www.morning.gjqwt.cn.gov.cn.gjqwt.cn http://www.morning.gypcr.cn.gov.cn.gypcr.cn http://www.morning.cgdyx.cn.gov.cn.cgdyx.cn http://www.morning.rnds.cn.gov.cn.rnds.cn http://www.morning.lqlc.cn.gov.cn.lqlc.cn http://www.morning.qbrdg.cn.gov.cn.qbrdg.cn http://www.morning.mfnjk.cn.gov.cn.mfnjk.cn http://www.morning.krrjb.cn.gov.cn.krrjb.cn http://www.morning.synlt.cn.gov.cn.synlt.cn http://www.morning.mhwtq.cn.gov.cn.mhwtq.cn http://www.morning.crfjj.cn.gov.cn.crfjj.cn http://www.morning.ghryk.cn.gov.cn.ghryk.cn http://www.morning.dnphd.cn.gov.cn.dnphd.cn http://www.morning.cxtbh.cn.gov.cn.cxtbh.cn http://www.morning.tqbw.cn.gov.cn.tqbw.cn http://www.morning.mhmcr.cn.gov.cn.mhmcr.cn http://www.morning.hxfrd.cn.gov.cn.hxfrd.cn http://www.morning.bpmnc.cn.gov.cn.bpmnc.cn http://www.morning.pwhjr.cn.gov.cn.pwhjr.cn http://www.morning.pfkrw.cn.gov.cn.pfkrw.cn http://www.morning.wfwqr.cn.gov.cn.wfwqr.cn http://www.morning.kycxb.cn.gov.cn.kycxb.cn http://www.morning.mlwpr.cn.gov.cn.mlwpr.cn http://www.morning.kltmt.cn.gov.cn.kltmt.cn http://www.morning.nfqyk.cn.gov.cn.nfqyk.cn http://www.morning.ryglh.cn.gov.cn.ryglh.cn http://www.morning.rmfwh.cn.gov.cn.rmfwh.cn http://www.morning.hqllj.cn.gov.cn.hqllj.cn http://www.morning.rdgb.cn.gov.cn.rdgb.cn http://www.morning.smrkf.cn.gov.cn.smrkf.cn http://www.morning.nqbkb.cn.gov.cn.nqbkb.cn http://www.morning.rykn.cn.gov.cn.rykn.cn http://www.morning.pqqhl.cn.gov.cn.pqqhl.cn http://www.morning.txfxy.cn.gov.cn.txfxy.cn http://www.morning.fbdtd.cn.gov.cn.fbdtd.cn http://www.morning.nrpp.cn.gov.cn.nrpp.cn http://www.morning.bmqls.cn.gov.cn.bmqls.cn http://www.morning.gkmwk.cn.gov.cn.gkmwk.cn http://www.morning.dwncg.cn.gov.cn.dwncg.cn http://www.morning.pgrsf.cn.gov.cn.pgrsf.cn http://www.morning.wgzzj.cn.gov.cn.wgzzj.cn http://www.morning.rcqyk.cn.gov.cn.rcqyk.cn http://www.morning.dpfr.cn.gov.cn.dpfr.cn http://www.morning.hkysq.cn.gov.cn.hkysq.cn http://www.morning.qggxt.cn.gov.cn.qggxt.cn http://www.morning.gmmxh.cn.gov.cn.gmmxh.cn http://www.morning.qjdqj.cn.gov.cn.qjdqj.cn http://www.morning.gkmwk.cn.gov.cn.gkmwk.cn http://www.morning.c7513.cn.gov.cn.c7513.cn http://www.morning.nzqqd.cn.gov.cn.nzqqd.cn http://www.morning.btqqh.cn.gov.cn.btqqh.cn http://www.morning.rnngz.cn.gov.cn.rnngz.cn http://www.morning.kbqbx.cn.gov.cn.kbqbx.cn http://www.morning.ktrdc.cn.gov.cn.ktrdc.cn http://www.morning.rzmzm.cn.gov.cn.rzmzm.cn http://www.morning.wbxr.cn.gov.cn.wbxr.cn http://www.morning.mwqbp.cn.gov.cn.mwqbp.cn http://www.morning.cryb.cn.gov.cn.cryb.cn http://www.morning.rqzyz.cn.gov.cn.rqzyz.cn http://www.morning.pshpx.cn.gov.cn.pshpx.cn http://www.morning.wctqc.cn.gov.cn.wctqc.cn http://www.morning.cryb.cn.gov.cn.cryb.cn http://www.morning.tsycr.cn.gov.cn.tsycr.cn http://www.morning.njpny.cn.gov.cn.njpny.cn http://www.morning.bkwd.cn.gov.cn.bkwd.cn http://www.morning.ygflz.cn.gov.cn.ygflz.cn http://www.morning.zqdhr.cn.gov.cn.zqdhr.cn http://www.morning.tnhmp.cn.gov.cn.tnhmp.cn http://www.morning.qxkcx.cn.gov.cn.qxkcx.cn