Очень медленно читать из базы данных - PullRequest
1 голос
/ 20 июня 2020

Я использую весеннюю загрузку с данными Spring jpa, hibernate и oracle.

На самом деле, в моей таблице около 10 миллионов записей, мне нужно выполнить некоторые операции, записать информацию в файл и после удаления записи.

Это базовый c sql запрос

select * from zzz where  status = 2;

Я провел тест без выполнения операции и удалил запись

    long start = System.nanoTime();
    int page = 0;
    Pageable pageable = PageRequest.of(page, LIMIT);

    Page<Billing> pageBilling = billingRepository.findAllByStatus(pageable);

    while (true) {
        for (Billing: pageBilling .getContent()) {
            //process
            //write to file
            //delete element
        }

        if (!pageBilling .hasNext()) {
            break;
        }

        pageable = pageBilling .nextPageable();
        pageBilling = billingRepository.findAllByStatus(pageable);

    }
    long end = System.nanoTime();
    long microseconds = (end - start) / 1000;
    System.out.println(microseconds + " to write");

Результат это плохо, с лимитом 10 000, на это ушло 157 минут, с 100 000 - 28 минут, с миллионами - 19 минут.

Есть ли лучшее решение для увеличения производительности?

1 Ответ

0 голосов
/ 20 июня 2020

Следующее может значительно улучшить производительность:

  1. Вы не должны повторять итерацию после первой страницы. Вместо этого удалите обработанные данные и снова выберите первую страницу. На самом деле вам не нужна страница, для которой вы можете закодировать ограничение в имени метода. Выбор поздних страниц довольно неэффективен.

  2. Процесс загрузки, обработки и удаления одной партии элементов должен выполняться в отдельной транзакции. В противном случае EntityManager будет содержать все когда-либо загруженные объекты, что очень сильно замедлит работу.

Если этого все еще недостаточно, вы можете посмотреть следующее:

Проверьте выполнение SQL. Это выглядит разумно? Если вы не рассмотрите возможность перехода на JdbcTemplate или NamedParameterJdbcTemplate с помощью метода query, который принимает RowCallbackHandler, вы должны иметь возможность загружать и обрабатывать все строки с помощью одного оператора выбора и в конце обрабатывать один оператор удаления для удаления все строки. Для этого необходимо, чтобы статус, который вы используете для фильтрации, в среднем не менялся.

Как выглядят планы выполнения? Если им покажется, что они проверят ваши индексы.

...