Spring 批次需要很长时间才能完成作业
Spring Batch taking long time to complete the Job
我正在处理 Spring 批处理应用程序。该应用程序从数据库中读取数据,处理并发送到 Kafka。
我需要从 parent-child 关系中的两个 table 读取数据。
喜欢:
Parent :
- 身份证、姓名
Child :
- 身份证,姓名,Parent_Id
我正在使用 JpaPagingItemReader。我正在读取来自 reader 的 Parent table 数据和来自进程的 Child 数据。
@Autowired
private JpaTransactionManager transactionManager;
@PersistenceContext
private EntityManager em;
public ItemStreamReader<Parent> reader() {
JpaPagingItemReader<Parent> itemReader = new JpaPagingItemReader<>();
try {
String sqlQuery = "SELECT * FROM PARENT";
JpaNativeQueryProvider<Parent> queryProvider = new JpaNativeQueryProvider<Parent>();
queryProvider.setSqlQuery(sqlQuery);
queryProvider.setEntityClass(Parent.class);
queryProvider.afterPropertiesSet();
itemReader.setEntityManagerFactory(em.getEntityManagerFactory());
itemReader.setPageSize(100);
itemReader.setQueryProvider(queryProvider);
itemReader.afterPropertiesSet();
itemReader.setSaveState(true);
}
catch (Exception e) {
System.out.println("BatchConfiguration.reader() ==> error " + e.getMessage());
}
return itemReader;
}
@Autowired
private ChildRepository childRepository;
@Bean
public ItemProcessor<Parent,ParentVO> opptyProcess() {
return new ItemProcessor<Parent, ParentVO>() {
@Override
public ParentVO process(Parent parent) throws JsonProcessingException {
ParentVO parentVO = new ParentVO();
parentVO.setId(parent.getId());
parentVO.setName(parent.getName());
List<Child> childList = childRepository.findByParentId(parent.getId());
if(childList != null && childList.size() > 0) {
for(Child child :childList) {
ChildVo childVO= new ChildVO();
childVO.setId(child.getId);
childVO.setName(child.getName());
childVO.setParentId(child.getParentId())
ParentVO.getChildList().add(childVO);
}
}
return parentVO;
}
};
}
@Bean
public Step step() {
return stepBuilderFactory.get("step1")
.<Parent, ParentVO>chunk(100)
.reader(reader())
.processor(process())
.writer(writer)
.taskExecutor(threadPool)
.transactionManager(transactionManager)
.throttleLimit(10)
.build();
}
我正在用 20k 条记录测试这个应用程序。这个应用程序的性能非常慢。每分钟它只能 read/process/write 100 条记录。如果我评论以下行,则需要 2 分钟才能完成工作。
List<Child> childList = childRepository.findByParentId(parent.getId());
if(childList != null && childList.size() > 0) {
for(Child child :childList) {
ChildVo childVO= new ChildVO();
childVO.setId(child.getId);
childVO.setName(child.getName());
childVO.setParentId(child.getParentId())
ParentVO.getChildList().add(childVO);
}
}
还有什么其他方法可以获取 Child table 数据并使此作业更快。
您基本上是在应用程序端执行 join
操作,这就是性能问题的原因。
您正在实施的模式与 driving query pattern, where a processor is used to enrich items returned by the reader. This pattern is known to suffer from the n+1 problem 相似,后者在某些情况下表现不佳。
我建议您在数据库端进行连接。关系数据库系统针对此类操作进行了很好的优化,如果您的应用程序抓取已经在数据库端加入的数据,您会注意到性能大幅提升。
我正在处理 Spring 批处理应用程序。该应用程序从数据库中读取数据,处理并发送到 Kafka。 我需要从 parent-child 关系中的两个 table 读取数据。
喜欢:
Parent : - 身份证、姓名
Child : - 身份证,姓名,Parent_Id
我正在使用 JpaPagingItemReader。我正在读取来自 reader 的 Parent table 数据和来自进程的 Child 数据。
@Autowired
private JpaTransactionManager transactionManager;
@PersistenceContext
private EntityManager em;
public ItemStreamReader<Parent> reader() {
JpaPagingItemReader<Parent> itemReader = new JpaPagingItemReader<>();
try {
String sqlQuery = "SELECT * FROM PARENT";
JpaNativeQueryProvider<Parent> queryProvider = new JpaNativeQueryProvider<Parent>();
queryProvider.setSqlQuery(sqlQuery);
queryProvider.setEntityClass(Parent.class);
queryProvider.afterPropertiesSet();
itemReader.setEntityManagerFactory(em.getEntityManagerFactory());
itemReader.setPageSize(100);
itemReader.setQueryProvider(queryProvider);
itemReader.afterPropertiesSet();
itemReader.setSaveState(true);
}
catch (Exception e) {
System.out.println("BatchConfiguration.reader() ==> error " + e.getMessage());
}
return itemReader;
}
@Autowired
private ChildRepository childRepository;
@Bean
public ItemProcessor<Parent,ParentVO> opptyProcess() {
return new ItemProcessor<Parent, ParentVO>() {
@Override
public ParentVO process(Parent parent) throws JsonProcessingException {
ParentVO parentVO = new ParentVO();
parentVO.setId(parent.getId());
parentVO.setName(parent.getName());
List<Child> childList = childRepository.findByParentId(parent.getId());
if(childList != null && childList.size() > 0) {
for(Child child :childList) {
ChildVo childVO= new ChildVO();
childVO.setId(child.getId);
childVO.setName(child.getName());
childVO.setParentId(child.getParentId())
ParentVO.getChildList().add(childVO);
}
}
return parentVO;
}
};
}
@Bean
public Step step() {
return stepBuilderFactory.get("step1")
.<Parent, ParentVO>chunk(100)
.reader(reader())
.processor(process())
.writer(writer)
.taskExecutor(threadPool)
.transactionManager(transactionManager)
.throttleLimit(10)
.build();
}
我正在用 20k 条记录测试这个应用程序。这个应用程序的性能非常慢。每分钟它只能 read/process/write 100 条记录。如果我评论以下行,则需要 2 分钟才能完成工作。
List<Child> childList = childRepository.findByParentId(parent.getId());
if(childList != null && childList.size() > 0) {
for(Child child :childList) {
ChildVo childVO= new ChildVO();
childVO.setId(child.getId);
childVO.setName(child.getName());
childVO.setParentId(child.getParentId())
ParentVO.getChildList().add(childVO);
}
}
还有什么其他方法可以获取 Child table 数据并使此作业更快。
您基本上是在应用程序端执行 join
操作,这就是性能问题的原因。
您正在实施的模式与 driving query pattern, where a processor is used to enrich items returned by the reader. This pattern is known to suffer from the n+1 problem 相似,后者在某些情况下表现不佳。
我建议您在数据库端进行连接。关系数据库系统针对此类操作进行了很好的优化,如果您的应用程序抓取已经在数据库端加入的数据,您会注意到性能大幅提升。