情景:有一個一條記錄有20個字段,共30萬條記錄的xlsx文件,文件大小大約30兆,需要將其內容讀取後寫入數據庫。
這意味着需要向數據庫寫入30萬條數據,讀取xlsx方面,用的是POI,用了幾種方式做,性能對比如下:
一、MyBatis的xml裏逐條寫入:一條記錄生成一條SQL語句並執行一次,這種做法性能過低,不作討論。
二、MyBatis的xml裏用foreach方式,一次寫入2000條數據
1.POI:XSSFWorkbook讀xlsx:
List<List<Object>> result = new ArrayList<>();
Workbook wb = new XSSFWorkbook(new File(filePath));
for (Sheet sheet : wb) {
for (Row row : sheet) {
List<Object> rowData = getRowData(row);
result.add(rowData);
}
}
wb.close();
return result;
這種方式在xlsx內有30萬條數據的情況下報錯。
2.POI:SAX模式讀xlsx:
File xlsxFile = new File(filePath);
OPCPackage p = OPCPackage.open(xlsxFile.getPath(), PackageAccess.READ);
Xlsx2ListData xlsx2ListData = new Xlsx2ListData(p, minColumns, null);
List<List<Object>> result = xlsx2ListData.process();
p.close();
return result;
使用該方法一次讀取30萬條數據,形成一個size=30萬的list,然後每次寫入2000條數據,耗時1320s。
3.POI:SAX方式讀取xlsx文件,讀取每一行調用RowDataProcesser:
File xlsxFile = new File(filePath);
OPCPackage p = OPCPackage.open(xlsxFile.getPath(), PackageAccess.READ);
Xlsx2ListData xlsx2ListData = new Xlsx2ListData(p, minColumns,
rowDataProcesser);
xlsx2ListData.process();
p.close();
該方式使用RowDataProcesser接口,讀取一行就寫入list,list滿後向數據庫批量寫入,同樣的機器,同樣的數據,耗時1356s
第二,第三種方式讀取xlsx文件分別耗時:13s,12s也就是說,數據庫IO佔了大部分時間。
結論:SAX模式讀取大文件(30萬條數據)向數據庫寫入的情景下,SAX模式的兩種讀取方式性能差距不大,真正的性能瓶頸是數據庫I/O,針對這個問題,嘗試增大list容量,減少數據庫IO次數。
將list容量增大至1萬,即每次向數據庫寫入1萬條數據。
結果報錯了:PacketTooBigException
目前還沒有找到更快的方法。