벌크 쿼리 ( Bulk Query )
。DB에 직접 대량 데이터를 한번에 삽입 / 수정 / 삭제를 수행하는 쿼리를 의미
▶ 한 행에 대해서 수행하는게 아닌, 여러 행을 일괄적으로 처리하는 방식
일괄처리방식 ( Batch Process )
。정의된 특정 작업을 그룹화하여 일괄적으로 처리하도록 구성하는 프로세스
▶ 반복적이면서 대규모 데이터 처리 시 용이
。1개 작업을 수행 후 DB I/O가 발생하는 작업을 각각 반복 시 매우 비효율적
▶ 메모리 내 영속성 컨텍스트 상 배치 사이즈만큼의 횟수의 작업 수행 후 flush()를 통해 일괄적으로 DB로 반영하는 과정을 반복하면 DB I/O 횟수가 감소하여 효율적
。배치 사이즈를 단위로 지정하여 각각 전체 작업에서 작업을 단위별로 분리 후 개별 작업을 작업 및 변경사항을 한꺼번에 DB에 반영하는 과정을 반복
▶ Batch Size = 50 이고 데이터 = 1000일때, flush()를 통한 20번의 DB I/O만 발생하므로 효율적
。이때, 메모리 상에 이전 배치 작업 데이터가 누적되어 쌓이면 OOM의 위험이 존재
▶ 영속성 컨텍스트의 경우 배치 작업에 사용된 Entity를 EntityManager객체.close()를 통해 비영속화 상태로 구성하여 자원 해제 이후 다음 배치 작업을 시작
。Spring Data JPA의 경우 saveAll()을 통해 벌크쿼리에 대한 배치작업을 자동으로 수행
。실패한 배치는 무시하고, 성공된 배치를 우선적으로 DB에 반영 후 실패한 배치에 대해서 다시 모아서 재작업을 수행
영속성 컨텍스트를 통한 배치작업 구현
。Batch Size = 50 이고 데이터 = 1000일때, EntityManager객체.flush()를 통한 20번의 DB I/O만 발생
。배치 작업에 사용된 Entity를 EntityManager객체.close()를 통해 비영속화 상태로 구성 후 다음 배치 작업을 시작하도록 설정하여 OOM을 차단.
。BATCH-SIZE = 50 일때, 데이터수 = 65인 경우 15개 데이터의 처리되지 않은 남은 Entity에 대해서 한번 더 flush() / close() 적용
public List<Item> saveAll(List<Item> items){
final int BATCH_SIZE = 50;
for(int i = 0 ; i < items.size() ; i++){
entityManager.persist(items.get(i));
if(i % BATCH_SIZE == 0 && i>0){
entityManager.flush();
entityManager.close();
log.info("FLUSH 완료");
}
}
entityManager.flush();
entityManager.close();
log.info("FLUSH 완료");
return items;
}