项目上有个导出 excel 场景发现很慢,怎么优化?
项目上有个导出 excel 场景发现很慢,怎么优化?
回答重点
1)先定位慢在哪儿?
需要定位导出 excel 慢在哪里:
- 业务逻辑慢?
- 数据库查询慢?
- excel 生成慢?
2)针对性解决慢的问题
如果是业务逻辑处理很慢,则需要优化调整逻辑,比如将一些在循环内的多次 RPC 调用,变成一次(或更少)的批量 RPC 调用。
如果是数据库查询慢,则查看 SQL 是都命中索引,是否有额外的排序逻辑等等。
一般情况下导出的场景都会分页查询数据库,可以将普通分页使用的 LIMIT offset,size 变成记录上一次查询的 id 为 lastId,然后下次查询的时候带上 lastId 作为查询条件。
例如:select * from table where id > lastId + (其他过滤条件) order by id asc limit size;
因为 LIMIT offset,size 的效率比较低,例如 limit 10000000,10,则是一直扫描到 10000000 后,跳过它们,再取接下来的 10 条数据,对数据库来说这需要大量的 I/O 操作(扫描这么多行)
至于最后 excel 生成慢的场景,一般只要避免一行一行写入即可。即批量写入数据,而不是一行一行写入。
3)多线程优化
上面优化过后,如果还想缩短导出的时间,则需要进行多线程操作。
将要导出的数据进行分片,比如以”地方“为分片依据,北京的一个 sheet、上海的一个 sheet 以此类推,多线程并发处理不同 sheet 数据的获取和写入(或者多个 excel 文件都行,最后生成一个 zip 包输出就好了)。
大数据量的情况下注意使用流式导出,防止占用过多内存,POI 使用 SXSSF,EasyExcel 默认就是流式导出。
扩展知识
多线程导出代码示例
使用 EasyExcel 导出, EasyExcel 默认使用流式写入功能(SXSSF),减少内存消耗,支持大数据量导出。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| 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; }
public void exportDataForPlace(String place, String filePath) { List<Data> dataList = getDataByPlaceFromDB(place);
EasyExcel.write(filePath, Data.class) .sheet(place) .doWrite(dataList); }
public void export() throws InterruptedException, ExecutionException { List<String> places = Arrays.asList("北京", "上海", "广州", "深圳", "杭州");
ExecutorService executorService = Executors.newFixedThreadPool(places.size()); List<Future<?>> futures = new ArrayList<>();
String filePath = EXPORT_DIR + "/places.xlsx";
for (String place : places) { Future<?> future = executorService.submit(() -> { try { exportDataForPlace(place, filePath); } catch (Exception e) { e.printStackTrace(); } }); futures.add(future); }
for (Future<?> future : futures) { future.get(); }
executorService.shutdown(); System.out.println("mianshiya Excel export has been completed."); } }
|