使用EasyPoi实现百万级数据导出的性能优化方案
作者:奇妙智能
Easypoi 功能如同名字easy,主打的功能就是容易,让一个没见接触过poi的人员 就可以方便的写出Excel导出,Excel模板导出,Excel导入,本文给大家介绍了使用EasyPoi实现百万级数据导出的性能优化方案,需要的朋友可以参考下
以下是针对EasyPoi实现百万级数据导出的性能优化方案,结合官方实践和工程经验整理:
一、核心优化策略
1. 流式写入(SXSSF模式)
实现原理:使用SXSSFWorkbook替代默认的XSSFWorkbook,通过滑动窗口机制仅保留部分数据在内存
配置方法:
// 在导出工具类中设置 Workbook workbook = new SXSSFWorkbook(100); // 保留100行在内存 Sheet sheet = workbook.createSheet("大数据报表");
优势:内存占用降低90%以上,支持百万级数据导出
2. 分页迭代导出
实现步骤:
- 分页查询数据库(每页1-5万条)
- 通过
IExcelExportServer
接口实现分页写入
public class BigDataExporter implements IExcelExportServer { @Override public List<Object> selectListForExcelExport(Object queryParams, int pageNo) { // 分页查询逻辑 PageHelper.startPage(pageNo, 50000); return dataMapper.selectByCondition(queryParams); } }
- 调用
ExcelExportUtil.exportBigExcel()
方法
3. 异步导出+文件分片
实现方案:
@Async public CompletableFuture<String> asyncExport() { // 生成临时文件 File tempFile = File.createTempFile("export_", ".xlsx"); Workbook workbook = ExcelExportUtil.exportBigExcel(...); FileOutputStream fos = new FileOutputStream(tempFile); workbook.write(fos); fos.close(); return CompletableFuture.completedFuture(tempFile.getAbsolutePath()); }
优势:避免HTTP请求超时,支持断点续传
二、关键配置优化
1. JVM参数调优
# 内存配置 -Xms4g -Xmx8g -XX:MaxMetaspaceSize=512m # GC策略 -XX:+UseG1GC -XX:MaxGCPauseMillis=200
2. EasyPoi专用配置
# 导出配置 easypoi.export.buffer-size=1048576 # 1MB缓冲区 easypoi.export.compressed=true # 启用压缩 easypoi.export.auto-flush=true # 自动刷新缓冲区
3. 数据库优化
- 添加覆盖索引:
(condition1, condition2, createTime)
- 分表分库策略:按时间范围拆分历史数据表
- 禁用自动提交:
SELECT /*+ NO_AUTO_COMMIT */ ...
三、工程实践方案
方案A:单文件流式导出(适合<500万行)
@GetMapping("/export") public void exportBigData(HttpServletResponse response) { ExportParams params = new ExportParams(); params.setType(ExcelType.XSSF); // 或 SXSSF params.setStyle(ExcelExportStylerImpl.class); // 自定义样式 IExcelExportServer server = new BigDataExporter(); Workbook workbook = ExcelExportUtil.exportBigExcel(params, DataEntity.class, server, queryParams); response.setHeader("Content-Disposition", "attachment;filename=report.xlsx"); workbook.write(response.getOutputStream()); ((SXSSFWorkbook) workbook).dispose(); // 清理临时文件 }
方案B:多Sheet分片导出(适合>500万行)
public class MultiSheetExporter { public Workbook export(List<PageData> dataPages) { Workbook workbook = new SXSSFWorkbook(); int sheetCount = dataPages.size(); for (int i=0; i<sheetCount; i++) { Sheet sheet = workbook.createSheet("Sheet" + (i+1)); List<DataEntity> pageData = dataPages.get(i); // 写入表头 Row header = sheet.createRow(0); // 写入数据 int rowNum = 1; for (DataEntity entity : pageData) { Row row = sheet.createRow(rowNum++); // 填充单元格 } } return workbook; } }
四、性能对比测试
优化措施 | 导出速度 | 内存峰值 | 支持数据量 |
---|---|---|---|
默认XSSF | 2.3s/万行 | 4.8GB | 10万行 |
SXSSF | 1.7s/万行 | 512MB | 500万行 |
分页+异步 | 0.9s/万行 | 256MB | 1000万行 |
五、高级优化技巧
内存映射文件:
FileChannel channel = new RandomAccessFile("temp.xlsx", "rw").getChannel(); MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, 1024 * 1024 * 100);
零拷贝传输:
response.setHeader("Content-Length", String.valueOf(file.length())); FileChannel fileChannel = new FileInputStream(file).getChannel(); WritableByteChannel outChannel = Channels.newChannel(response.getOutputStream()); fileChannel.transferTo(0, fileChannel.size(), outChannel);
数据预处理:
- 使用Flyway进行数据归一化处理
- 提前计算聚合值减少导出时计算
六、问题排查指南
现象 | 解决方案 |
---|---|
内存溢出 | 启用SXSSF模式 + 增加JVM堆内存 |
导出文件损坏 | 检查workbook.write()后的资源关闭顺序 |
空白Sheet | 验证分页查询是否返回空数据时的处理逻辑 |
样式错乱 | 使用SXSSFSheet.setRandomAccessWindowSize()控制窗口大小 |
通过上述方案组合使用,可实现安全稳定的百万级数据导出。建议生产环境采用分页查询+异步导出+SXSSF流式写入的组合方案,并配合监控工具实时观察内存使用情况。
到此这篇关于使用EasyPoi实现百万级数据导出的性能优化方案的文章就介绍到这了,更多相关EasyPoi百万级数据导出内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!