#excel #postgresql #spring-boot #spring-data-jpa
#преуспеть #postgresql #пружинный ботинок #spring-data-jpa #excel #весенняя загрузка
Вопрос:
У меня есть приложение, в котором пользователь будет загружать файл Excel (.xlsx или .csv) с более чем 10 000 строками с одним столбцом «PartID», содержащим значения для поиска в базе данных
Я буду считывать значения Excel и сохранять их в объекте list и передавать список в качестве параметра в метод поиска репозитория Spring Boot JPA, который встроен в запрос предложения внутри:
// 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 query неэффективно для огромного списка данных.
Как я могу оптимизировать приведенный выше сценарий или написать новый оптимизированный запрос?
Кроме того, пожалуйста, дайте мне знать, есть ли оптимизированный способ чтения файла Excel, отличный от вышеупомянутого фрагмента кода
Это было бы очень полезно!! Заранее спасибо!
Комментарии:
1. В Stackoverflow есть примеры использования
VALUES
соединения вместо ifin
. Вы пробовали это?2. @madflow, я пробовал это. Я хотел бы знать, есть ли какой-либо другой оптимизированный способ сделать для огромного списка значений
3. @LaurenzAlbe, поскольку я буду получать списки из пользовательского интерфейса через API, я обязан перемещать большие списки между приложением и базой данных. Я не знаю, как эффективно передать список
4. @LaurenzAlbe, боюсь, мне не совсем понятно ваше утверждение:(. Не могли бы вы поделиться каким-либо примером запроса?
Ответ №1:
Если список действительно огромен, вы никогда не будете молниеносными.
Я вижу несколько вариантов:
-
Отправьте запрос с большим
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), (101), (43), ...; -- 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. скорее всего, будет медленнее, если список не будет действительно большим.
Комментарии:
1. Большое вам спасибо! Я попробую все эти способы и обновлю статус каждого решения.