Спящий режим перерасчет сброшенных объектов, когда сброс используется несколько раз в одной транзакции

#java #hibernate #spring-data-jpa

Вопрос:

Я готовлю приложение spring, используя jpa с hibernate, чтобы сохранить несколько сотен миллионов строк в бд.

Я провожу некоторые тесты на меньшем источнике данных с 5 миллионами строк. Чтобы не хранить все данные в памяти до конца обработки, я сбрасываю данные каждые n-е строки. Код выглядит так:

     AtomicLong counter = new AtomicLong();

    destinationService.doInTransaction(() -> {

        IntStream.range(0, (int) numberOfPages)
                .boxed()
                .peek(integer -> log.debug("Getting page: {}", integer   1))
                .flatMap(i -> sourceRepository.findAll(PageRequest.of(i, pageSize)).get())
                .flatMap(ETLService::map)
                .peek(destinationService::save)
                .map(measurement -> counter.getAndIncrement())
                .peek(i -> {
                    if (i % jdbcBatchSize == 0) {
                        log.debug("Flushing. Objects counted: {}", i);
                        destinationService.flush();
                    }
                })
                .count();
        return null;
    });
 

Я включил показатели сеанса, и они показывают, что сброшено гораздо больше объектов:

 2021-09-18 23:58:10.807  INFO 4680 --- [           main] i.StatisticalLoggingSessionEventListener : Session Metrics {
    3140100 nanoseconds spent acquiring 1 JDBC connections;
    0 nanoseconds spent releasing 0 JDBC connections;
    21488800 nanoseconds spent preparing 584 JDBC statements;
    0 nanoseconds spent executing 0 JDBC statements;
    251780906500 nanoseconds spent executing 5828 JDBC batches;
    0 nanoseconds spent performing 0 L2C puts;
    0 nanoseconds spent performing 0 L2C hits;
    0 nanoseconds spent performing 0 L2C misses;
    2494336312500 nanoseconds spent executing 584 flushes (flushing a total of 1702357144 entities and 0 collections);
    0 nanoseconds spent executing 0 partial-flushes (flushing a total of 0 entities and 0 collections)
}
 

Однако, если бы я удалил часть промывки из потока, она показывала бы один промыв с правильным количеством строк.

  2021-09-18 23:04:55.562  INFO 11476 --- [           main] i.StatisticalLoggingSessionEventListener : Session Metrics {
    4869500 nanoseconds spent acquiring 1 JDBC connections;
    0 nanoseconds spent releasing 0 JDBC connections;
    2912100 nanoseconds spent preparing 1 JDBC statements;
    0 nanoseconds spent executing 0 JDBC statements;
    250479981900 nanoseconds spent executing 5827 JDBC batches;
    0 nanoseconds spent performing 0 L2C puts;
    0 nanoseconds spent performing 0 L2C hits;
    0 nanoseconds spent performing 0 L2C misses;
    302878192900 nanoseconds spent executing 1 flushes (flushing a total of 5826561 entities and 0 collections);
    0 nanoseconds spent executing 0 partial-flushes (flushing a total of 0 entities and 0 collections)
}
 

Почему при большем количестве сбросов в спящий режим перерасчет объектов?

Комментарии:

1. Я точно не знаю, но если вы считаете, что это ошибка, пожалуйста, создайте проблему в трекере проблем( hibernate.atlassian.net ) с тестовым случаем( github.com/hibernate/hibernate-test-case-templates/blob/master/… ), который воспроизводит проблему.