Batch Processing 의 필요성과 MySQL 에서의 Batch Insert
Summary
Batch Processing 의 필요성
Batch Processing 은 대량의 데이터나 작업을 일괄적으로 처리하는 것을 말한다. 여러 개의 작업을 한꺼번에 처리하므로 처리 시간을 단축시키고, 자동화하여 비용을 줄일 수 있다.
대표적인 예시로 거래 내역이나 로그 데이터를 처리할 때 일일 배치 처리를 수행하여 요약 및 분석을 수행
한다.
또한, 이미 대량으로 쌓여있는 파일이나 동영상에 일괄적으로 어떤 작업을 수행해야 할 때도 필요할 것이다.
MySQL 에서의 Batch Insert 를 할 때의 문제점
MySQL 에서는 기본키 생성 전략으로 auto increment 가 주로 사용된다
MySQL 에서는 primary key 를 관리하는 방법으로 대체로 auto increment 방식을 선호하고 실제로 이를 다른 방식으로 구현하는 것보다 굉장히 간편하다.
- 휴대폰 번호 혹은 주민등록번호와 같이 Natural Key 를 Primary Key 로 사용하는 것이 좋은 테이블
- 복합키를 사용하는 것이 좋은 테이블
이렇게 두 가지 케이스를 제외하면 거의 auto increment 를 사용한다고 볼 수 있다.
Hibernate 와 auto increment 전략 간의 충돌
하이버네이트에서는 영속성 컨텍스트의 데이터에 대한 flushing 을 최대한 지연하는 전략을 통해 성능상의 이점을 취하려고 한다.
하지만, Identity 전략에서 자동으로 생성되는 키 값을 얻기 위해서는 Insert 쿼리를 날려야 한다. 따라서, 이 두 가지 전략 간에
상충되는 부분이 발생하므로 MySQL 의 Identity 전략에서 Hibernate 는 배치 처리를 지원하지 않는다
Hibernate Reference - 12.2. Session batching
참고로, MySQL 외의 Sequence 전략이 사용 가능한 database 에서는 채번을 batch 단위로 하는 전략을 통해 batch processing 의 최적화를 할 수도 있다.
JDBC 의 batchUpdate 함수를 이용
따라서, JPA 가 내부적으로 사용하고 있는 jdbc 를 이용하여 직접 batch processing 을 구현함으로써 이 문제를 해결 할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
public void bulkInsert(List<Post> posts) {
var sql = String.format("""
INSERT INTO `%s` (memberId, contents, createdDate, createdAt)
VALUES (:memberId, :contents, :createdDate, :createdAt)
""", TABLE);
SqlParameterSource[] params = posts
.stream()
.map(BeanPropertySqlParameterSource::new)
.toArray(SqlParameterSource[]::new);
namedParameterJdbcTemplate.batchUpdate(sql, params);
}
SqlParameterSource 의 Array 타입을 params 로 선언하여 batchUpdate 함수의 인자로 넘겨주면,
1
2
3
4
5
6
7
INSERT INTO
TABLE
VALUES
(value1, value2, value3),
(value1, value2, value3),
(value1, value2, value3),
...
와 같은 형태로 넘겨줄 수 있다.