[alibaba/easyexcel]循环多次写入,每次写入10000条数据,数据的写入越写越慢,写到50万数据的时候,需要8s

2023-04-10 794 views
0
异常代码
WriteSheet writeSheet = EasyExcel.writerSheet("Sheet").build();
            // 写入数据
            try (ExcelWriter excelWriter = EasyExcel.write(xlsxFileName, exportResultVO.getClass())
                .registerWriteHandler(new FillHeadMergeStrategy())
                .includeColumnFieldNames(includeColumnFieldNames)
                .build()) {
                // 分页查询
                for (int j = 0; j <= MAX_COUNT; j++) {
                    long start1 = System.currentTimeMillis();
                    List<?> result = function.apply(maxId);
                    long end1 = System.currentTimeMillis();
                    log.info("function.apply end:" + (end1 - start1));
                    if (CollectionUtils.isEmpty(result)) {
                        // 防止创建excel报错
                        excelWriter.write(result, writeSheet);
                        break;
                    }
                    // 写入excel
                    long start2 = System.currentTimeMillis();
                    excelWriter.write(result, writeSheet);
                    long end2 = System.currentTimeMillis();
                    log.info("excelWriter.write end:" + (end2 - start2));
                    maxId = getMaxId(maxId, result);
                    result.clear();
                }
            }
问题描述

大批量导出大概100万数据,每次写入10000数据,开始写入的时候也很快,监控了 excelWriter.write(result, writeSheet),发现在写入几十万数据之后,这个方法写入数据很慢,大概8s左右

回答

3

建议查看GC时间和拦截器里面是否有内存泄漏的情况

3
result.clear();

建议查看GC时间和拦截器里面是否有内存泄漏的情况

监控了gc正常,为了防止内存泄露特意在最后一行吧list清空了,result.clear();

2

把gclog贴上来

8

把gclog贴上来

image

7

我这里测试是没有问题的,我觉得问题应该在你的解析器 FillHeadMergeStrategy 这里

4

建议你把FillHeadMergeStrategy这个东西先去掉,然后测试一下执行时间

6

@Override public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<WriteCellData<?>> list, Cell cell, Head head, Integer integer, Boolean isHead) { // 当前行 int curRowIndex = cell.getRowIndex(); // 当前列 int curColIndex = cell.getColumnIndex(); Sheet sheet = writeSheetHolder.getSheet(); List mergedRegions = sheet.getMergedRegions(); if (!isHead) { return; } List headNameList = head.getHeadNameList(); int size = headNameList.size(); for (int i = 0; i < mergedRegions.size(); i++) { CellRangeAddress cellAddresses = mergedRegions.get(i); // 当前单元格被合并了,并且在表头最后一行就删除 if (cellAddresses.getFirstRow() >= curRowIndex && cellAddresses.getFirstColumn() == curColIndex && cellAddresses.getFirstRow() == size - 1) { // 删除合并单个格 log.info("delete merge cell : {} ", cell.getStringCellValue()); sheet.removeMergedRegion(i); mergedRegions.remove(i); i--; } } }

建议你把FillHeadMergeStrategy这个东西先去掉,然后测试一下执行时间

FillHeadMergeStrategy是防止表头合并单元格的,不至于拖累吧

3

我这里确实无法复现你的问题, 写入了100W条记录都很快,要不你给一个完整demo。

9

基本上就是完整代码了,还是很慢

    WriteSheet writeSheet = EasyExcel.writerSheet("Sheet").build();
    for (int i = 0; i <= pageCount; i++) {
        // 生成excel文件名称
        String xlsxFileName = ExportUtils.getXlsxFileName(exportEnum, i + "");
        pathList.add(xlsxFileName);
        // 写入数据
        try (ExcelWriter excelWriter = EasyExcel.write(xlsxFileName, exportResultVO.getClass())

            .includeColumnFieldNames(includeColumnFieldNames)
            .build()) {
            // 分页查询
            for (int j = 0; j <= MAX_COUNT; j++) {
                long start1 = System.currentTimeMillis();

                List<SpartDetailManagementPO> result = new ArrayList<>();
                for (int k = 0; k < 10000; k++) {
                    SpartDetailManagementPO spartDetailManagementQueryDTO = new SpartDetailManagementPO();
                    spartDetailManagementQueryDTO.setSpartNumber(i + "");
                    result.add(spartDetailManagementQueryDTO);
                }
                long end1 = System.currentTimeMillis();
                log.info("function.apply end:" + (end1 - start1));
                if (CollectionUtils.isEmpty(result)) {
                    // 防止创建excel报错
                    excelWriter.write(result, writeSheet);
                    break;
                }
                // 写入excel
                long start2 = System.currentTimeMillis();
                excelWriter.write(result, writeSheet);
                long end2 = System.currentTimeMillis();
                log.info("excelWriter.write end:" + (end2 - start2));

                result.clear();
            }
        }
    }
1

目前是导出一个100万的数据,应该只会生成一个excel

3

你的实体,你的数据我都没有 我怎么复现呢。 你要给我一个能复现的代码 而不是贴一个方法而已