如何用Apache POI写入300万行Excel及SXSSF大数据导出无响应问题
Apache POI SXSSF处理百万级数据导出的问题解答
首先给你拍板:SXSSF完全能处理百万级甚至千万级的数据导出——它本身就是Apache为解决XSSF内存溢出痛点专门设计的,靠把超出内存窗口的行写入磁盘临时文件来降低内存占用,生产环境里我见过用它导出两三千万行数据的真实案例,所以你的核心疑问答案是肯定的。
那你到110万行就无响应,大概率是某个环节的优化没做到位,我给你捋几个最可能的原因和解决思路:
可能的问题点
- 内存吃紧导致GC疯狂停顿:
你这130+列的每行数据量不小,就算用SXSSF,如果从数据库拉取数据的批次太大(比如一次拉10万行),或者JVM堆内存给的不够,很容易导致内存占用过高,GC频繁触发甚至出现Full GC长时间停顿,看起来就像代码“无响应”。 - 数据库分页查询性能拉胯:
要是你用的是LIMIT offset, size这种偏移量分页,当offset到100万级别时,数据库要扫描前面所有数据才能返回结果,耗时会指数级上升,看起来也像代码卡住了。 - 磁盘IO拖后腿:
SXSSF的临时文件默认存在系统临时目录,如果这个目录在机械硬盘上,或者磁盘空间不足,写入速度会慢到离谱,导致程序卡住。 - 未及时刷盘或清理资源:
要是你没手动调用flushRows(),或者处理完一批数据后没及时关闭ResultSet、清理实体对象,内存里堆积的东西越来越多,也会拖慢程序。
针对性优化建议
- 调整数据库分页方式:
把偏移量分页改成基于主键的连续分页,比如用WHERE id > last_processed_id LIMIT batch_size,这样数据库每次只需要扫描少量数据,性能会稳定很多。 - 严格控制批次大小与内存:
每次从数据库拉取的行数别贪多,建议5000-10000行就够(根据你每行的列数调整);同时给JVM加足够的堆内存,比如启动参数设-Xmx4G(如果服务器配置允许,加到6G、8G更好)。另外,创建SXSSFWorkbook时指定内存窗口大小,比如new SXSSFWorkbook(1000)——意思是只在内存保留1000行,超出的直接写磁盘。 - 优化磁盘IO:
把SXSSF的临时文件目录指定到SSD磁盘上,用SXSSFWorkbook.setTempFileCreationStrategy方法自定义临时文件路径;写完每个批次后手动调用sheet.flushRows(),强制把内存里的数据刷到磁盘。 - 加日志监控定位卡点:
在代码里加日志,比如每处理完1万行、每写完一个工作表就打印日志,记录耗时和当前行数,这样你就能精准知道是数据库查询慢了,还是写入磁盘慢了。 - 及时清理资源:
处理完一批数据后,立刻关闭ResultSet、Statement,把没用的实体对象置为null,必要时可以手动调用System.gc()(别频繁调用,批次结束后调用一次就行)。
按这些思路调整后,处理200多万行数据应该就顺畅了。
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

