Batch Insert로 대량의 데이터 처리하기
실무에서 대량의 데이터를 넣게 될 때, 몇만건 이상이 된다면 데이터를 저장하는 과정이 매우 오래 걸리는걸 볼 수 있습니다. 이때는 JPA의 saveAll 메서드가 아닌, jdbcTemplate의 batch insert를 직접 구현하는 방법으로 데이터를 좀 더 빠르고 유연하게 넣을 수 있는 모습을 볼 수 있습니다. 이번 글에는 batch insert에 대해 알아보겠습니다.
Batch Insert란?
여러 행을 연결해서 한 번에 입력하여 Insert 하는 것을 Batch Insert라고 합니다. 그러므로 한 트랜잭션에
처리되는 행 수를 지정하여 처리할 수 있습니다.
JPA의 saveAll
JPA에서 여러 개 단위의 Insert를 제공하는 메서드인 saveAll은 List 객체를 담아 사용하지만, 등록할 데이터 수만큼 Insert 쿼리가 나가는 것을 볼 수 있습니다. 대량의 데이터 기준으로 saveAll 메서드를 사용하게 될 경우 JPA의 특성인 쓰기 지연으로 인해 아주 오랜 시간 동안 INSERT 쿼리가 발생하고 있는 것을 볼 수 있습니다.
JPA Batch Insert
saveAll에서 많은 행의 Insert 쿼리를 줄일 수 있는 방법으로, order_inserts 속성이 있습니다. 다음과 같이 BatchSize와 order_inserts의 사용을 명시해 준다면 BatchSize의 수만큼 insert할때 하나의 쿼리로 묶이는 것을 볼 수 있습니다.
spring:
datasource:
url: ~/rewriteBatchedStatements=true&profileSQL=true 추가 해줄것 !
jpa:
hibernate:
ddl-auto: create
properties:
hibernate:
show-sql: true
jdbc:
batch_size: 100
order_inserts: true
order_updates: true
JPA Batch Insert의 한계
위와 같이 Batch Insert를 할 수 있지만, 모든 엔티티 속성에 대해 이런 기능들을 제공하는 것은 아닙니다. 실무에서 MySql을 사용하게 된다면 Auto Increment 기능을 제공하는 GenerationType.IDENTITY를 PK로 많이 선언하는데 이는 Batch Insert가 되지 않습니다. JPA는 쓰기 지연으로 모든 데이터를 트랜잭션이 끝날 때 DB에 반영하는데, 해당 기능은 DB에 이미 의존되어 사용되고 있는 기능이기 때문에 적용되지 않습니다.
JDBC Template Batch Insert
어떠한 상황에서도 Batch Insert를 수행할 수 있는 방법으로는 Spring JDBC에서 제공하는 Batch Insert가 있습니다. 이를 사용할 경우 IDENTITY 전략일 경우에도 정상적으로 Insert 쿼리가 한방에 나가는 것을 볼 수 있습니다. 아래는 사용 예시입니다.
@Override
public void insertBulkPost(List<Post> postList) {
jdbcTemplate.batchUpdate("INSERT INTO POST (CONTENT,TITLE,MEMBER_ID) VALUES (?,?,?)", new BatchPreparedStatementSetter() {
@Override
public void setValues(PreparedStatement ps, int i) throws SQLException {
Post post = postList.get(i);
ps.setString(1, post.getContent());
ps.setString(2, post.getTitle());
ps.setLong(3, post.getMember().getId());
}
@Override
public int getBatchSize() {
return postList.size();
}
});
}
이번 글에는 JPA에서 대량의 데이터를 저장할 때 성능적인 이슈를 해결할 수 있는 Batch Insert 설정과 JDBC Template Batch Insert에 대해 알아보았습니다. 이를 통해 DB에 데이터를 저장할 때 성능적인 부분에서 많은 이점을 얻을 것 같습니다. 앞으로 JPA에서 대량의 데이터를 저장할 때 이를 참고하여 진행해야겠습니다. 읽어주셔서 감사합니다.
'Spring' 카테고리의 다른 글
[JPA] ManyToMany를 사용하지 않는다면? (0) | 2024.03.02 |
---|---|
[JPA] JPA Pagination 처리 방법 (Pageable, Page, Slice) (0) | 2024.02.28 |
[JPA] JPQL개념과 사용법 패턴 정리 (0) | 2024.02.22 |
[JPA] QueryDSL의 페이징 카테시안 곱 문제 해결 방법 (1:N Pagination) (0) | 2024.02.16 |
[JPA] QueryDSL에서 JPA N+1 문제 해결하기 (0) | 2024.02.13 |