大量数据导出到 Excel 表的问题

常用导出方式

  • POI (Apache)
    • org.apache.poi.hssf.usermodel.HSSFWorkbook
    • org.apache.poi.xssf.streaming.SXSSFWorkbook
  • EasyExcel(阿里巴巴)
    • com.alibaba.excel.ExcelWriter

比较内存消耗情况

单线程测试用例

  • 由于 GC 的影响,这些测试数据不是非常准确,但是还是有一些参考意义。
  • 测试导出 6 万条记录,观察导出的过程中,内存的消耗情况:
    • HSSFWorkbook
      在这里插入图片描述
    • SXSSFWorkbook
      在这里插入图片描述
    • ExcelWriter
      在这里插入图片描述
      在这里插入图片描述

多线程测试用例

  • 10 个线程同时导出包含 6 万条记录的 Excel。在各个线程准备就绪时,打印内存信息,当全部完成时,再一次打印内存信息:
    • HSSFWorkbook 的导出:
      • 正常导出,消耗 920M左右内存,最慢 27秒。
      • 在这里插入图片描述
    • SXSSFWorkbook 的导出:
      • 正常导出,消耗内存 183 M,最慢 12 秒。
      • 在这里插入图片描述
  • 20 个线程同时导出包含 6 万条记录的 Excel。在各个线程准备就绪时,打印内存信息,当全部完成时,再一次打印内存信息。
    • HSSFWorkbook 的导出:
      • 内存溢出,导出失败:
      • 在这里插入图片描述
    • SXSSFWorkbook 的导出:
      • 正常导出,内存消耗 388 M,最慢的线程需要 17秒。
      • 在这里插入图片描述
  • 30 个线程同时导出包含 6 万条记录的 Excel。在各个线程准备就绪时,打印内存信息,当全部完成时,再一次打印内存信息。
    • HSSFWorkbook 在 20 个线程同时导出时,就已经内存溢出,这里不需要再测试。
    • SXSSFWorkbook :
      • 正常导出,内存消耗440M,耗时 25 秒。
      • 在这里插入图片描述
  • 40 个线程同时导出包含 6 万条记录的 Excel。在各个线程准备就绪时,打印内存信息,当全部完成时,再一次打印内存信息。
    • HSSFWorkbook 在 20 个线程同时导出时,就已经内存溢出,这里不需要再测试。
    • SXSSFWorkbook :
      • 正常导出,内存消耗670M,耗时 33 秒。
      • 在这里插入图片描述
  • 50 个线程同时导出包含 6 万条记录的 Excel。在各个线程准备就绪时,打印内存信息,当全部完成时,再一次打印内存信息。
    • HSSFWorkbook 在 20 个线程同时导出时,就已经内存溢出,这里不需要再测试。
    • SXSSFWorkbook :
      • 正常导出,内存消耗560M(触发了内存回收,博主测了几组都差不多),耗时 38 秒。
      • 在这里插入图片描述
  • 100 个线程同时导出包含 6 万条记录的 Excel。在各个线程准备就绪时,打印内存信息,当全部完成时,再一次打印内存信息。
    • HSSFWorkbook 在 20 个线程同时导出时,就已经内存溢出,这里不需要再测试。
    • SXSSFWorkbook :
      • 正常导出,内存消耗269M(触发了内存回收,博主测了几组都差不多),耗时 75 秒。
      • 在这里插入图片描述

简单总结与分析

  • 从节省内存的角度看,SXSSFWorkbook 和 EasyExcel 相对于 HSSFWorkbook 有很大的优势。所以,并发数稍微高点,HSSFWorkbook 就会撑爆内存,而SXSSFWorkbook 和 EasyExcel 不会有这个问题,只是导出稍微慢点。
  • 从导出速度上看,SXSSFWorkbook 和 EasyExcel 也比 HSSFWorkbook 快很多
  • SXSSFWorkbook 消耗的内存少。内存消耗少的主要原因是它引入了 rowAccessWindowSize 。
    • rowAccessWindowSize 的作用:
      • 在这里插入图片描述
  • EasyExcel 同样内存消耗低。它是如何实现降低内存消耗???
    • 楼主没有找到相关资料。
    • 尝试分析:
      • 要使得内存消耗小,肯定是把导出的数据存放到了内存之外的地方——显然,只有硬盘了。
        • 博主猜测,EasyExcel 有和 SXSSFWorkbook 类似的机制,当存入的数据超出阈值之后,就先缓存到硬盘。在SXSSFWorkbook 中,阈值由 rowAccessWindowSize 确定,默认是 100 行。
      • 博主多次执行 EasyExcel 的导出程序,发现很多时候 usedMemory 都很低。
        • 博主猜测,如果不是碰巧,就是 EasyExcel 实现了控制 GC 的逻辑。
  • 如何选择:
    • SXSSFWorkbook 和 EasyExcel 任选一个。博主本人更倾向于使用 Apache 的 SXSSFWorkbook 。
      • 文档多是一方面
      • 和 HSSFWorkbook 一脉相承,都是 Workbook 的派生类。因此,我们要把 HSSFWorkbook 重构成 SXSSFWorkbook 会非常简单,只需要修改生成 Workbook 的具体类型,并在最后导出的时候,调用 SXSSFWorkbook 的 dispose() 方法即可。
      • SXSSFWorkbook 内存消耗少的原因很透明-上面已经分析,不再赘述。而 EasyExcel 博主不太了解。但是经过博主简单的测试,EasyExcel 和 SXSSFWorkbook 不相伯仲,所以也就没有必要纠结 EasyExcel 。
    • 注意,EasyExcel GitHub上的测试图,是 EasyExcel 和 HSSFWorkbook (而不是 SXSSFWorkbook )的比较结果。

测试代码

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值