Java导出xlsx格式文件 处理50万条记录的高性能低内存方案咨询
50万条数据导出xlsx性能优化方案
你当前逐行写入的逻辑本身没有大问题,核心性能瓶颈来自于全量50万条POJO驻留内存、以及非流式的Excel写入方式会缓存所有单元格数据,可从以下几个维度优化:
1. 数据库查询层优化(从根源降低内存占用)
- 不要一次性拉取全量50万条数据到内存,替换为流式查询/分批分页查询:
- JDBC层面设置
fetchSize参数(比如设置为1000),让数据库按批次返回结果,不会一次性把全量数据加载到JVM堆内存 - 常用ORM框架都有对应实现:比如MyBatis可以用
ResultHandler做流式结果处理,JPA可以设置hibernate.jdbc.fetch_size属性
- JDBC层面设置
- 只查询导出需要的字段,不要
select *,减少数据传输量和POJO对象的内存占用
2. Excel写入层优化(避免全量数据驻留内存)
- 抛弃传统POI用户模式(
XSSFWorkbook),改用流式写入实现:- 首选阿里EasyExcel:底层封装了POI的流式能力,自动处理磁盘刷写,写入50万条数据内存占用稳定在几十MB,不需要手动管理批次
- 也可以用POI官方的
SXSSFWorkbook:通过设置内存中保留的行数量(比如默认100行),超过阈值的行会自动写入临时磁盘文件,最后合并为xlsx,注意使用完需要手动调用dispose()方法删除临时文件
- 不要先生成全量POJO列表再遍历写入,做到查询一批、转换一批、写入一批:每处理完一批数据,该批次的POJO对象就可以被垃圾回收,不需要持有全量数据的引用
3. 细节优化项
- 复用单元格样式:POI对单Excel文件的
CellStyle数量有上限,且样式对象占用内存较高,相同格式的单元格必须复用同一个样式实例,不要逐行创建新样式 - 关闭不需要的Excel特性:如果不需要公式、宏、单元格批注这类功能,写入时直接关闭对应配置,减少额外性能消耗
- 单sheet数据量不要超过xlsx的上限1048576行,50万条数据单sheet足够承载,如果后续数据量增长可以提前做自动拆sheet逻辑
代码示例(EasyExcel实现)
// 导出POJO定义,指定列映射 @Data public class ExportDataPO { @ExcelProperty("用户ID") private Long userId; @ExcelProperty("用户名") private String userName; // 其余导出字段按业务补充 } // 流式查询+分批写入核心逻辑 try (ExcelWriter writer = EasyExcel.write(response.getOutputStream(), ExportDataPO.class).build()) { WriteSheet sheet = EasyExcel.writerSheet("导出数据").build(); int pageNo = 1; int pageSize = 1000; while (true) { // 分批查询数据库 List<ExportDataPO> batchList = exportMapper.selectPageData(pageNo, pageSize); if (CollectionUtils.isEmpty(batchList)) { break; } // 直接写入当前批次数据 writer.write(batchList, sheet); pageNo++; } }
内容的提问来源于stack exchange,提问作者Bapu
相关产品推荐
相关产品推荐

