Spring Data JPA에서는 컬렉션을 저장하는 메서드를 지원하고있다.

해당 메서드를 사용해 컬렉션을 저장하면 데이터가 단건씩 INSERT되는 문제가 있다.
데이터가 적다면 문제가 없겠지만 대량의 데이터가 단건씩 저장되면
네트워크, DB 비용이 많이 발생할 수 밖에 없다.
이 문제를 해결하기 위해서 2가지 방법이 존재한다.
- 쿼리를 직접 작성
- BatchSize 사용
1번 방법도 좋지만.. 귀찮기도하고 JPA Repository를 그대로 사용하고 싶다면 2번 방법이 좋을 것 같다.
배치 사이즈를 사용하는 방법은 다음과 같다.
- hibernate batch size 프로퍼티 값 설정
- 배치사이즈 만큼 묶어 전달
- JDBC reWriteBatchedInserts 파라미터 옵션 활성화
- 배치사이즈 만큼의 INSERT를 단일 쿼리로 reWrite 시켜준다
- 아쉽지만 PK가 AUTO_INCREMENT 방식일 때는 동작하지 않는다.
해당 옵션이 잘 동작하는지 테스트 하기위해 필요한 코드를 작성했고 설정을 바꿔가면서 테스트를 진행해 봤다.
@Transactional
public void bulkInsert() {
List<Member> members = IntStream.range(0, 300_000)
.mapToObj(Member::new)
.toList();
memberRepository.saveAll(members);
)
spring:
datasource:
url: jdbc:postgresql://127.0.0.1:5432/${DB_NAME}
username: ${DB_USERNAME}
password: ${DB_PASSWORD}
배치 사이즈 옵션별 시간 측정 실험 - 1
배치 관련 옵션 미사용
batch_size: 비활성화reWriteBatchedInserts: false

결과: 406.99초
아무런 옵션 값을 지정하지 않았기 때문에 단건씩 저장되는 것을 확인할 수 있다.
배치 사이즈 옵션별 시간 측정 실험 - 2
spring:
datasource:
url: jdbc:postgresql://127.0.0.1:5432/${DB_NAME}?reWriteBatchedInserts=true
username: ${DB_USERNAME}
password: ${DB_PASSWORD}
batch_size: 비활성화reWriteBatchedInserts: true
reWriteBatchedInserts 옵션만 true로 설정했지만 결과는 실험 - 1과 동일하다.
배치 사이즈 옵션별 시간 측정 실험 - 3
spring:
jpa:
properties:
hibernate:
jdbc:
batch_size: 100
order_inserts: true
order_updates: true
datasource:
url: jdbc:postgresql://127.0.0.1:5432/${DB_NAME}
username: ${DB_USERNAME}
password: ${DB_PASSWORD}
batch_size: 100reWriteBatchedInserts: false
배치 사이즈만 정의하고 reWriteBatchedInserts 옵션은 비활성화했다.

결과: 40.08초
이전 실험들과 비교했을 때 약 10배 빠른 응답을 보여줬다.
애플리케이션에서 만들어진 쿼리들을 배치 사이즈 만큼 묶어 전송하게 되어 빨라졌지만
아직까지 DB가 받는 쿼리는 여러개의 INSERT들이다.
배치 사이즈 옵션별 시간 측정 실험 - 4
spring:
jpa:
properties:
hibernate:
jdbc:
batch_size: 100
order_inserts: true
order_updates: true
datasource:
url: jdbc:postgresql://127.0.0.1:5432/${DB_NAME}?reWriteBatchedId=true
username: ${DB_USERNAME}
password: ${DB_PASSWORD}
batch_size: 100reWriteBatchedInserts: true
모든 옵션을 주고 테스트해봤다.

결과: 16.17초
로그를 봤을 때 우리가 원했던 배치사이즈 만큼의 insert가 정상적으로 수행되는 것을 확인할 수 있다!
실험 - 5
batch_size: 500reWriteBatchedInserts: true- 결과: 9.04초
실험 - 6
batch_size: 1000reWriteBatchedInserts: true- 결과: 8.88초
실험 - 7
batch_size: 2000reWriteBatchedInserts: true- 결과: 8.25초
결론
- batch_size 가 500이 넘어가는 시점 부터 성능 향상이 거의 없고,
사이즈가 너무 크면 오히려 성능이 감소했다. - 상황에 따라 적절한 batch_size 를 찾고 적용하자
- 더 높은 성능을 원한다면 MyBatis, JDBC Template을 사용