DB에 여러 건의 데이터를 넣는 방법

아마 레거시가 아닌 이상 스프링을 사용할 때 대부분 ORM 기술을 사용하고, Jpa를 사용할 것이다.

따라서 DB에 여러 건의 데이터를 넣는 방법을 정리하자면 4가지 정도를 생각할 수 있다.

  1. JPA의 save() 사용 ->  데이터 수 만큼 for 문으로 Insert
  2. JPA의 saveAll() 사용
  3. JPA의 Bulk Insert 사용
  4. JDBC Bulk Insert 사용

1. JPA - save() vs saveAll()

우선 SpringDataJpa에서 제공하는 save()와 saveAll()을 비교해보자.

기본적으로 save()와 saveAll() 모두 날리는 Insert 쿼리 수는 1000개로 동일하다.

하지만 save()와 saveAll()의 다른 점은 아래 그림에서 보듯 트랜잭션 수 이다.

1-1. save()

save() 메서드 실행 시 매번 트랜잭션을 열고 Insert 쿼리를 날린 후 닫는다.

for 문으로 1000건의 데이터를 삽입하면 1000번의 트랜잭션을 열고 닫게 된다.

한번의 트랜잭션에서 모든 Insert를 처리하는게 아니므로 도중에 에러 발생가 발생하면

그동안 Insert 된 데이터가 모두 롤백되는게 아니라 에러 발생 전에 Insert 된 데이터는 DB에 남는다.

1-2. saveAll()

반면 saveAll()은 1000건의 데이터를 삽입해도 트랜잭션은 1번만 열고 닫는다.

따라서 트랜잭션 수가 훨씬 적으므로 성능이 더 좋다.

하지만 기본적으로 날리는 Insert 쿼리 수는 1000개로 동일하기 때문에 여전히 성능적으로 문제가 있을 수 있다.


2. JPA - Bulk Insert

Jpa에서도 하이버네이트 구현체에서 Bulk Insert 기능을 지원한다.

하지만 ID 생성 전략이 Auto Increment(IDENTITY)일 때는 사용할 수 없다는 단점이 있다.

ID 생성 전략이 Auto Increment이면 PK는 레코드가 DB에 INSERT 될때 생성된다.

따라서 PK를 확인하기 위해 INSERT 쿼리를 하나씩 날려줘야하므로 Bulk Insert 기능과 호환이 안된다.

만약 ID 생성 전략을 Auto Increment를 사용하지 않는다면 Jpa를 사용하면서 Bulk Insert를 사용할 수 있다.

이 경우 saveAll()의 Insert 쿼리 수에 대한 문제를 해결할 수 있다.


3. JDBC - Bulk Insert

ID 생성 전략이 Auto Increment인 프로젝트에서는 하이버네이트의 Bulk Insert 기능을 사용할 수 없다.

그렇다면 Auto Increment를 사용하면 어떻게 Bulk Insert를 사용할 수 있을까?

정답은 JDBC Template을 사용하는 것이다.

기본적인 쿼리는 Jpa를 사용하고, Bulk Insert가 필요한 경우 JDBC Template을 사용하는 Repository를 따로 만든다.

JDBC로 Bulk Insert를 하는 경우 Jpa를 사용할 때와는 다르게 엔티티를 영속화 해도 영속성 컨텍스트 관리를 하지 않는다.

따라서 이에 따르는 오버 헤드를 줄일 수 있고, Insert 쿼리도 1번으로 해결하니 성능상으로 매우 큰 이점을 얻을 수 있다.

 

이렇게 하면 사용하는 DB 기술이 여러개가 돼서 관리하기 불편할 수는 있을것 같다.

하지만 성능 상으로는 훨씬 이점을 볼 수 있기 때문에 적절하게 사용하면 될것 같다.


4. 실습

위에서 언급한 내용들을 실습해보았다.

코드가 궁금하다면 이쪽 글을 확인하면 참고가 될것이다.

 

참고자료

 

Bulk insert(벌크 연산)를 활용하여 쿼리 성능 개선해보기

문제 발생배경 이번에는 제가 맡은 도메인 서비스를 개발하다가 만난 "벌크 연산(Bulk Insert)" 관련 이슈에 대해 다루어보고자 합니다. JPA saveAll() 의 한계 save() 를 300번 수행한다. 기존에는 JPA 의 sa

haon.blog

 

+ Recent posts