回答重点
- 先定位慢在哪儿?需要定位导出 excel 慢在哪里
- 业务逻辑慢?
- 数据库查询慢?
- excel 生成慢?
- 针对性解决慢的问题
- 如果是业务逻辑处理很慢,则需要优化调整逻辑,比如将一些在循环内的多次 RPC 调用,变成一次(或更少)的批量 RPC 调用。
- 如果是数据库查询慢,则查看 SQL是都命中索引,是否有额外的排序逻辑等等。一般情况下导出的场景都会分页查询数据库,可以将普通分页使用的 Limit offset,size变成记录上一次查询的 id 为 lastld,然后下次查询的时候带上 lastld 作为查询条件。例select * from table where id >lastId +(其他过滤条件) order by id asc limit size ;因为 Limit offset,size的效率比较低,例 limnit 100000,10,则是一直扫描到10000后,跳过它们,再取接下来的10条数据,对数据库来说这需要大量的 IO 操作 (扫描这么多行)。详情可以看大分页 limit
- excel 生成慢的话一般只要避免一行一行写入即可。即批量写入数据,而不是一行一行写入。
- 多线程优化:上面优化过后,如果还想缩短导出的时间,则需要进行多线程操作。
将要导出的数据进行分片,比如以”地方“为分片依据,北京的一个sheet、上海的一个sheet 以此类推,多线程并发处理不同sheet 数据的获取和写入(或者多个 excel)文件都行,最后生成一个zp 包输出就好了)。大数据量的情况下注意使用流式导出,防止占用过多内存,POI使用 SXSSF,EasyExcel默认就是流式导出。
public class ExcelExportService {
private static final String EXPORT_DIR = "path/to/export/directory"; // 临时文件存储目录
//从数据库查询数据
public List<Data> getDataByPlace(String place) {
List<Data> dataList = new ArrayList<>();
...
return dataList;
}
// 数据导出:根据地方分片生成不同的 Sheet
public void exportDataForPlace(String place, String filePath) {
List<Data> dataList = getDataByPlaceFromDB(place);
// 使用 EasyExcel 写入数据到 Excel 文件的不同 Sheet
EasyExcel.write(filePath, Data.class)
.sheet(place) // 每个地方对应一个 Sheet
.doWrite(dataList);
}
// 执行导出任务,采用多线程并发
public void export() throws InterruptedException, ExecutionException {
// 1. 定义地方列表
List<String> places = Arrays.asList("北京", "上海", "广州", "深圳", "杭州");
// 2. 设置线程池来并发处理不同地方的导出任务,此为 demo,真实环境线程池需要提前定义,
// 不可每次执行都创建
ExecutorService executorService = Executors.newFixedThreadPool(places.size());
List<Future<?>> futures = new ArrayList<>();
// 3. 创建 Excel 文件路径
String filePath = EXPORT_DIR + "/places.xlsx";
// 4. 执行每个地方的导出任务
for (String place : places) {
Future<?> future = executorService.submit(() -> {
try {
exportDataForPlace(place, filePath); // 导出数据到对应的 Sheet
} catch (Exception e) {
e.printStackTrace();
}
});
futures.add(future);
}
// 5. 等待所有任务完成
for (Future<?> future : futures) {
future.get();
}
// 6. 关闭线程池
executorService.shutdown();
System.out.println("mianshiya Excel export has been completed.");
}
}
更多详情可以看整合EasyExcel - 实现百万数据导入导出