Batch Processing 의 필요성과 MySQL 에서의 Batch Insert

Batch Processing 의 필요성

Batch Processing 은 대량의 데이터나 작업을 일괄적으로 처리하는 것을 말한다. 여러 개의 작업을 한꺼번에 처리하므로 처리 시간을 단축시키고, 자동화하여 비용을 줄일 수 있다. 대표적인 예시로 거래 내역이나 로그 데이터를 처리할 때 일일 배치 처리를 수행하여 요약 및 분석을 수행 한다. 또한, 이미 대량으로 쌓여있는 파일이나 동영상에 일괄적으로 어떤 작업을 수행해야 할 때도 필요할 것이다.

MySQL 에서의 Batch Insert 를 할 때의 문제점

MySQL 에서는 기본키 생성 전략으로 auto increment 가 주로 사용된다

MySQL 에서는 primary key 를 관리하는 방법으로 대체로 auto increment 방식을 선호하고 실제로 이를 다른 방식으로 구현하는 것보다 굉장히 간편하다.

  1. 휴대폰 번호 혹은 주민등록번호와 같이 Natural Key 를 Primary Key 로 사용하는 것이 좋은 테이블
  2. 복합키를 사용하는 것이 좋은 테이블

이렇게 두 가지 케이스를 제외하면 거의 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),
    ...

와 같은 형태로 넘겨줄 수 있다.

comments powered by Disqus