实现产出 1: 场景优化
每日一句诗词
loading...
loading...
介绍
在测试环境中,文件导出感觉不出来性能上的差异。在完成一些需求后,导师采纳了我的代码上线了生产环境。在此之前,我已经对导出功能进行了一些优化,体现在,除去了原代码中出现的循环查库,将其进行提前预处理,以及添加了可根据条件进行导出的功能(原来的代码只有全量导出)。次日,导师跟我说,导出速度慢,具体量值:3分钟导出4-5万条数据。
初步实现
导师给我的方案是:将导出数据量进行控制,只要从导出天数算起,X天的数据。在那一刻,我也并没有多去想,而是执行他给的任务。这并不困难,我只需要在对应的查询上,添加一个条件即可。项目用的是MyBatis-plus,我找到了那一个方法,添加了一个wrapper,就完成了效果。
1 | wrapper.ge(A::getCreateTime, LocalDate.now().minusDays(EXPORT_DAY)); |
测试效果:
筛选完数据后,导出来的数据量大概在2万条左右,导出时间在2分钟左右。emmm….效果并没有很理想
因为本质上,这一方案并没有从技术层面上去解决!!!
分析
初步优化:先问AI
EasyExcel 是一种轻量级的用于读写 Excel 文件的库,但是在使用时可能会遇到导出速度慢的问题。以下是一些可能影响导出速度的因素:
数据量大:大量数据行和列会显著增加处理时间和内存消耗。
复杂的数据格式:如果每个单元格都需要复杂的样式设置(如字体、颜色、对齐方式等等),则会增加处理时间。
IO性能:磁盘IO速度慢或者网络磁盘访问延迟,都会影响导出的速度。
写入方式不优化:一次写入大量数据,可能导致内存占用高或者写入速度慢。
硬件性能:计算机的CPU、内存等硬件性能不够强大时,性能瓶颈也会显现。
多线程与并发:EasyExcel 本身对于复杂并发的处理不是特别优化,如果有多线程的需求,没有有效的线程管理和负载均衡,可能导致性能下降。
文件大小:Excel文件本身达到一定大小后,文件的读写性能会显著下降。
JVM参数:分配给JVM的内存不够,导致频繁的垃圾回收(GC),影响性能。
为解决这些问题,可以尝试以下优化方法:
分批写入
简化格式设置
优化硬件
调优JVM参数
采用流式导出
- 多线程处理
- 减少文件大小
- 使用其他工具
通过这些方法,可以在一定程度上提高EasyExcel的导出速度。
- 分批
- 多线程处理
1 | // 大致代码 通过Gava的partition进行分组,使用 CountDownLatch 进行多线程写如不同的sheet |
测试 报错了! EasyExcel并不支持多线程。
1 | Exception in thread "pool-2-thread-1" org.apache.poi.ooxml.POIXMLException: org.apache.poi.openxml4j.exceptions.InvalidOperationException: You can't add a part with a part name derived from another part ! [M1.11] |
但是听过很多次说Easyexcel的并行导入,怎么现在实战不行了?
AI分析+博客:最终原因是单个ExcelWriter不支持多线程
持续优化
将创建ExcelWriter移入for循环
1 | // 大致代码 通过Gava的partition进行分组,使用 CountDownLatch 进行多线程写如不同的sheet |
高兴测试
发现接口还是一分多钟,优化不是很明显,都打算放弃了,看到博客写可能不是EasyExcel的问题,是代码的问题。对啊都没分析过代码的耗时,死盯着EasyExcel了。
排查
- 启动 arthas
根据jps找到对应的java进程选择
- 使用 trace 跟踪方法
1 | trace 全限定类名 方法名 --skipJDKMethod false |
—skipJDKMethod让jdk自带的方法也打印出来
steam流的collect操作耗时严重!!!
这里是一段DTO转VO的操作
后续的修改
在查询过程中 只选择VO需要的字段 ,对于一些逻辑转换直接在SQl层面进行一些函数转换(可能不太好),删除DTO转VO的代码
这是整体导出时间:1.8min -> 16s 这个提升还是不错哒!