У меня есть 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 минут