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 相似,后者在某些情况下表现不佳。

我建议您在数据库端进行连接。关系数据库系统针对此类操作进行了很好的优化,如果您的应用程序抓取已经在数据库端加入的数据,您会注意到性能大幅提升。