Весенняя партия занимает много времени, чтобы завершить работу - PullRequest
0 голосов
/ 29 апреля 2020

Я работаю над пакетным приложением Spring. Это приложение считывает данные из БД, обрабатывает и отправляет в Кафку. Мне нужно прочитать данные из двух таблиц в родительско-дочерних отношениях.

Как:

Родитель: - Id, Name

Child: - Id, Name, Parent_Id

Я использую JpaPagingItemReader. Я читаю данные родительской таблицы из программы чтения и дочерние данные из процесса.

    @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();
    }

Я тестирую это приложение с записями по 20 тыс. Производительность этого приложения очень низкая. Каждую минуту он может читать / обрабатывать / писать только 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 и ускорить выполнение этого задания.

1 Ответ

0 голосов
/ 29 апреля 2020

Вы в основном выполняете операцию join на стороне приложения, и это является причиной вашей проблемы с производительностью.

Реализуемый вами шаблон похож на шаблон запроса управления где процессор используется для обогащения предметов, возвращаемых читателем. Известно, что этот шаблон страдает от проблемы n + 1 , которая в некоторых случаях работает плохо.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...