alibaba / easyexcel

快速、简洁、解决大文件内存溢出的java处理Excel工具
https://easyexcel.opensource.alibaba.com
Apache License 2.0
31.64k stars 7.46k forks source link

2.2.20版本导出速度优化30% #3417

Open SWQXDBA opened 11 months ago

SWQXDBA commented 11 months ago

版本2.2.20

我在导出一个5万行的excel时,有20个列,用时在7秒左右。 通过火焰图分析,发现有大量时间(1.6秒左右)卡在了 addJavaObjectToExcel方法的beanMap.containsKey(name)上

image

而这个beanMap.containsKey会交给net.sf.cglib.beans.FixedKeySet类执行 image

而FixedKeySet并没有重写contains方法,所以其实际上会被交给AbstractCollection的contains方法执行比较。 image 导致了o(n)的复杂度。

解决办法: 想个办法把FixedKeySet类替换掉 image

经过测试 替换后的导出时间由7秒降低到了4秒左右

ljluestc commented 2 months ago

import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import com.alibaba.excel.write.metadata.WriteSheet;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.VerticalAlignment;

import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class ExcelExport {

    public static void main(String[] args) {
        // 创建测试数据
        List<TestData> dataList = generateTestData(50000);

        // 导出Excel
        exportExcel(dataList, "output.xlsx");
    }

    public static void exportExcel(List<TestData> dataList, String fileName) {
        try (FileOutputStream outputStream = new FileOutputStream(fileName)) {
            ExcelWriterBuilder writerBuilder = new ExcelWriterBuilder();
            ExcelWriter excelWriter = writerBuilder.file(outputStream).build();

            WriteSheet writeSheet = new WriteSheet();
            writeSheet.setSheetName("Sheet1");

            // 设置表头样式
            writeSheet.setHead(null);
            writeSheet.setHorizontalCellStyle(null);

            // 写入数据
            excelWriter.write(dataList, writeSheet);
            excelWriter.finish();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static List<TestData> generateTestData(int rowCount) {
        List<TestData> dataList = new ArrayList<>();
        for (int i = 0; i < rowCount; i++) {
            TestData testData = new TestData();
            testData.setId(i);
            testData.setName("Name " + i);
            testData.setValue("Value " + i);
            // 添加其他字段...
            dataList.add(testData);
        }
        return dataList;
    }

    public static class TestData {
        @ExcelProperty(index = 0)
        private Long id;

        @ExcelProperty(index = 1)
        private String name;

        @ExcelProperty(index = 2)
        private String value;

        // 其他字段...

        // 省略 getter 和 setter 方法
    }
}