Как оптимизировать массовые обновления в режиме гибернации? - PullRequest
0 голосов
/ 11 февраля 2019

У меня есть ETL, который выполняет массовые обновления для группы объектов.Локально это выполняется очень быстро, при отправке обновлений на удаленный сервер процесс значительно медленнее, на величины больше 10. Из-за конфиденциальности я не могу опубликовать какой-либо реальный код, но то, что публикуется, очень похоже на реальную вещь.

Немного фона

  • Стандартный проект с пружинной загрузкой
  • Стандартные модели JPA с автоматически сгенерированным идентификатором и без каких-либо объединений
  • Все репозитории наследуют CrudRepository<T, ID>
  • Все пакетные обновления вызывают следующий метод CrudRepository repository.saveAll(objects);

Я пробовал следующие вещи:

  • Поместите все проанализированные объекты в относительно большой пул потоков и вызовите repository.saveAll(objects); и дождитесь завершения

application.properties

spring.main.web-application-type=none
spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults=false
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
logging.level.root=INFO

Модель JPA, очень похожая на настоящую.

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table
public class Item {

    @Id
    @GeneratedValue
    @Column(name = "id", updatable = false, nullable = false)
    private Long id;

    @Column
    private String name;
}

Служба обновлений

@Primary
@Service
public class GenericUpdateServiceImpl implements UpdateService {

    @Override
    public void update(GenericEntityRepository repository, List<?> items) {
        repository.saveAll(items);
    }
}

Как обновления добавляются в пул потоков, затем дождитесь завершения пула потоков.У объектов нет идентификатора во время обновления

    private void parseForSheet(Sheet sheet, SheetParserProvider parserProvider, ParserState parserState, ExecutorService threadPool) {

        List<GenericParser> parsers = parserProvider.getParsersForSheet(sheet);

        if (!parsers.isEmpty()) {

            for (GenericParser parser : parsers) {
                List<?> items = parser.parse(sheet, parserState);
                threadPool.submit(getRunnableForItems(sheet, parser, items));
            }

            if (LOG.isDebugEnabled()) {
                LOG.debug(sheet.getSheetName());
            }
        }
    }

    private Runnable getRunnableForItems(Sheet sheet, GenericParser parser, List<?> items) {
        return () -> {
            if (!items.isEmpty()) {

                Object item = items.get(0);
                Optional<GenericEntityRepository> repositoryOp = repositoryProvider.getRepositoryForClass(item.getClass());
                repositoryOp.ifPresent(repo -> {

                    // run updates
                    updateService.update(repo, items);

                    if (LOG.isDebugEnabled()) {
                        LOG.debug(String.format("updated %d items for sheet %s and parser %s",
                                items.size(),
                                sheet.getSheetName(),
                                parser.getClass().getSimpleName()
                        ));
                    }
                });
            }
        };
    }

Я ожидаю, что переход от локальной базы данных к удаленной базе данных будет немного длиннее, но не в 10 раз длиннее.База данных запрашивает не используя спящий режим относительно быстро.При локальном анализе одного файла это занимает менее 30 секунд, при анализе файла в удаленной базе данных - около 10 минут

...