SXSSFWorkbook & XSSFWorkbook 效率比拼

起因

最近正在接触POI中的SXSSFWorkbook,要说起为什么会接触这个货,那就要说最近的一个项目了

这个项目需要将10w多条数据写入Excel,但是整个逻辑执行过程一直伴随着OOM

经过

于是我用Java VisuaalVM工具进行了一番查证,并在OOM的时候获取了dump文件,打开发现我了个擦,里面有两个货占据了大量的空间:

1、org.apache.xmlbeans.impl.store.Xobj$ElementXobj    占据空间425312843

2、org.apache.xmlbeans.impl.store.Xobj$AttrXobj            占据空间403268798

既然找到OOM的真凶那么久相分析一下这个到底是个啥

经过查阅资料发现原来是POI的坑,XSSFWorkbook在创建Excel、或者说写Excel的时候内存开销是很大的。

于是乎apache的POI项目推出了一个实现大数据量的流式版本XSSFWorkbook,也称之为SXSSFWorkbook,它允许了我们编写非常大的文件而不会耗尽内存,因为在任何时候只有行的可配置部分保存在内存中,例如合并区域,注释等。

下面我进行了一组测试来进一步阐述问题,当然HSSFWorkbook我就不说了,小娃娃一般

测试代码原理很简单,循环100w次插入100w条行数据,观察Excel生成情况

public static void test1(){
        try {
            long t1 = System.currentTimeMillis();
            SXSSFWorkbook workbook = new SXSSFWorkbook();
            workbook.createSheet("aaa");
            SXSSFSheet aaa = workbook.getSheetAt(0);
            for (int i=0;i<1000000;i++){
                aaa.createRow(i);
                aaa.getRow(i).createCell(0).setCellValue("aaaaaaaaaaaaaaaaaaaaaaa");
                aaa.getRow(i).createCell(1).setCellValue("aaaaaaaaaaaaaaaaaaaaaaa");
                aaa.getRow(i).createCell(2).setCellValue("aaaaaaaaaaaaaaaaaaaaaaa");
                aaa.getRow(i).createCell(3).setCellValue("aaaaaaaaaaaaaaaaaaaaaaa");
                aaa.getRow(i).createCell(4).setCellValue("aaaaaaaaaaaaaaaaaaaaaaa");
            }
            OutputStream outputStream = null;
            // 打开目的输入流,不存在则会创建
            outputStream = new FileOutputStream("J:\\out.xlsx");
            workbook.write(outputStream);
            outputStream.close();
            long t2 = System.currentTimeMillis();
            System.out.println("SXSSFWorkbook : 100w条数据写入Excel 消耗时间:"+ (t2-t1));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void test2(){
        try {
            long t1 = System.currentTimeMillis();
            XSSFWorkbook workbook = new XSSFWorkbook();
            workbook.createSheet("aaa");
            XSSFSheet aaa = workbook.getSheetAt(0);
            for (int i=0;i<1000000;i++){
                aaa.createRow(i);
                aaa.getRow(i).createCell(0).setCellValue("aaaaaaaaaaaaaaaaaaaaaaa");
                aaa.getRow(i).createCell(1).setCellValue("aaaaaaaaaaaaaaaaaaaaaaa");
                aaa.getRow(i).createCell(2).setCellValue("aaaaaaaaaaaaaaaaaaaaaaa");
                aaa.getRow(i).createCell(3).setCellValue("aaaaaaaaaaaaaaaaaaaaaaa");
                aaa.getRow(i).createCell(4).setCellValue("aaaaaaaaaaaaaaaaaaaaaaa");
            }
            OutputStream outputStream = null;
            // 打开目的输入流,不存在则会创建
            outputStream = new FileOutputStream("J:\\out2.xlsx");
            workbook.write(outputStream);
            outputStream.close();
            long t2 = System.currentTimeMillis();
            System.out.println("XSSFWorkbook : 100w条数据写入Excel 消耗时间:"+ (t2-t1));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

测试结果:

emmmm 好吧 内存溢出 那我把数据量调小点

可以看到SXSSFWorkbook确实优化很多

没有更多推荐了,返回首页