问题描述
我有一个应用程序,用户将上载具有10,000行以上的excel文件(.xlsx或.csv),其中单列“ partId”包含要在数据库中查找的值
我将读取excel值并将其存储在list对象中,并将该列表作为参数传递给内部构建IN子句查询的Spring Boot JPA存储库find方法:
// Read excel file
stream = new ByteArrayInputStream(file.getBytes());
wb = WorkbookFactory.create(stream);
org.apache.poi.ss.usermodel.Sheet sheet = wb.getSheetAt(wb.getActiveSheetIndex());
Iterator<Row> rowIterator = sheet.rowIterator();
while(rowIterator.hasNext()) {
Row row = rowIterator.next();
Cell cell = row.getCell(0);
System.out.println(cell.getStringCellValue());
vinList.add(cell.getStringCellValue());
}
//JPA repository method that I used
findByPartIdInAndSecondaryId(List<String> partIds);
我阅读了许多文章,在上述情况下,我也遇到了同样的情况,即使用IN查询无法处理大量数据。
如何优化上述方案或编写新的优化查询?
此外,请让我知道,除了上述代码片段之外,是否还有优化的读取excel文件的方式
那会很有帮助!!预先感谢!
解决方法
如果列表确实很大,您将永远不会快如闪电。
我看到几个选项:
-
发送一个带有大型
IN
列表的查询,就像您在问题中提到的那样。 -
构造一个带有大
VALUES
子句的联接语句:SELECT ... FROM mytable JOIN (VALUES (42),(101),(43),...) AS tmp(col) ON mytable.id = tmp.col;
-
使用这些值创建一个临时表并与之连接:
BEGIN; CREATE TEMP TABLE tmp(col bigint) ON COMMIT DROP;
然后选择
COPY tmp FROM STDIN; -- if Spring supports COPY
或
INSERT INTO tmp VALUES (42),...; -- if not
然后
ANALYZE tmp; -- for good statistics SELECT ... FROM mytable JOIN tmp ON mytable.id = tmp.col; COMMIT; -- drops the temporary table
其中最快的最好由您的案例的反复试验确定;我认为不能说其中一种方法总是会击败其他方法。
一些注意事项:
-
解决方案1.和2.可能会产生非常大的语句,而解决方案3.可能会分成较小的块。
-
解决方案3.除非列表很大,否则很有可能会变慢。