오늘의 인기 글
최근 글
최근 댓글
Today
Total
01-07 01:55
관리 메뉴

우노

[Kotlin] Bulk Insert 본문

Web_App/Kotlin

[Kotlin] Bulk Insert

운호(Noah) 2025. 1. 3. 15:22

Bulk Insert란?

  • Bulk Insert는 데이터베이스에 여러 개의 데이터를 한 번에 삽입하는 기법으로,
  • 여러 번의 Single Insert 대신 한 번에 여러 레코드를 삽입하여 속도와 효율성을 개선할 수 있습니다.

Single Insert vs Bulk Insert

  • Single Insert

    • 데이터를 하나씩 삽입하는 방식입니다.

        INSERT INTO table1 (col1, col2) VALUES (val11, val12);
    • 여러 번 반복되는 경우

        INSERT INTO table1 (col1, col2) VALUES (val11, val12);
        INSERT INTO table1 (col1, col2) VALUES (val21, val22);
        INSERT INTO table1 (col1, col2) VALUES (val31, val32);
  • Bulk Insert

    • 여러 개의 데이터를 한 번에 삽입하는 방식입니다.

        INSERT INTO table1 (col1, col2) VALUES
        (val11, val12),
        (val21, val22),
        (val31, val32);

Bulk Insert의 장점

  • 속도 개선: 한 번의 네트워크 호출로 여러 개의 데이터를 삽입하여 성능이 향상됩니다.
  • 리소스 절약: 네트워크 호출 횟수와 데이터베이스 연결을 줄여 시스템 자원을 절약할 수 있습니다.
  • 트랜잭션 관리: 여러 데이터를 하나의 트랜잭션으로 처리하여 일관성을 유지하고, 오류 발생 시 전체 작업을 롤백할 수 있습니다.

JPA와 JDBC에서 Bulk Insert 처리 방법

  • JPA의 saveAll() 사용하기

    • JPA는 saveAll() 메서드를 통해 여러 데이터를 한 번에 저장할 수 있습니다.

    • 하지만 내부적으로 반복적으로 save()를 호출하여 데이터를 개별적으로 처리하므로 진정한 Bulk Insert가 아님

      • save() : N개의 트랜잭션과 N개의 쿼리
      • saveAll() : 1개의 트랜잭션과 N개의 쿼리
    • 문제점

      • Hibernate의 쓰기 지연(Write-Behind) 전략
        • 데이터는 영속성 컨텍스트에 저장되고 트랜잭션이 커밋될 때 INSERT 쿼리가 실행됩니다.
        • 하지만 IDENTITY 전략을 사용하면, 각 엔티티의 ID를 알기 위해 매번 INSERT가 실행되어 Batch Insert가 불가능합니다.
      • 영속성 컨텍스트의 메모리 문제
        • 많은 데이터를 한 번에 저장하면 메모리 사용량이 증가하고 성능 저하가 발생합니다.
      • 성능 문제
        • JPA의 saveAll()은 개별 쿼리를 실행하므로 네트워크 호출이 많아지고 속도가 느려질 수 있습니다.
    • 해결 방법

      • ID 생성 전략 변경

        • IDENTITY 대신 SEQUENCE 또는 TABLE 전략을 사용하여 ID 값을 미리 생성할 수 있습니다.
      • Batch Insert 활성화

        • Hibernate 설정을 통해 Batch Insert를 활성화합니다.

            spring.jpa.properties.hibernate.jdbc.batch_size=30
            spring.jpa.properties.hibernate.order_inserts=true
            spring.jpa.properties.hibernate.order_updates=true
  • JDBC의 batchUpdate 사용하기

    • JDBC는 데이터베이스에 최적화된 Batch Insert 기능을 제공합니다.

    • JdbcTemplate의 batchUpdate() 메서드를 사용하면 여러 데이터를 효율적으로 삽입할 수 있습니다.

      String sql = "INSERT INTO table1 (col1, col2) VALUES (?, ?)";
      
      jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
        @Override
        public void setValues(PreparedStatement ps, int i) throws SQLException {
            ps.setString(1, dataList.get(i).getCol1());
            ps.setString(2, dataList.get(i).getCol2());
        }
      
        @Override
        public int getBatchSize() {
            return dataList.size();
        }
      });
  • Native SQL을 사용한 Bulk Insert

    • Spring Data JPA는 Native SQL을 지원합니다.

    • 이를 통해 직접 SQL 쿼리를 실행하여 효율적으로 Bulk Insert를 처리할 수 있습니다.

        @Query(value = "INSERT INTO table1 (col1, col2) VALUES :values", nativeQuery = true)
        void bulkInsert(@Param("values") List<Object[]> values);

Bulk Insert의 성능 비교

방법 10000건 처리 시간 장점 단점
JPA saveAll() 느림 (~5초) 코드 간결, 트랜잭션 관리 자동화 개별 INSERT 쿼리 실행으로 성능 저하
JDBC batchUpdate() 빠름 (~1초) 최적화된 성능, 네트워크 호출 감소 직접 쿼리 작성 필요
Native SQL 빠름 (~1초) 데이터베이스 기능 활용 가능 유지보수가 어렵고 JPA의 장점 활용 불가

Bulk Insert 시 주의사항

  • MySQL의 max_allowed_packet 설정
    • MySQL에서 한번에 보낼 수 있는 데이터 크기 제한이 max_allowed_packet 설정값을 넘지 않도록 주의해야 합니다.
    • 너무 큰 데이터를 한 번에 보내지 않도록 배치 크기를 조절하는 것이 중요합니다.
  • 메모리 관리
    • 대량 데이터를 처리할 경우 메모리 부족 문제가 발생할 수 있습니다.
    • 배치 크기를 조정하여 메모리 사용량을 관리하세요.
  • 롤백 비용
    • 배치 처리 중 오류가 발생하면 전체 트랜잭션이 롤백되므로, 배치 크기를 적절히 조정하여 롤백 비용을 최소화해야 합니다.

결론

  • Bulk Insert는 대량 데이터를 효율적으로 삽입할 수 있는 기법으로, 성능 향상리소스 절약이 가능합니다.
  • JPA를 사용할 때는 Hibernate Batch Insert 설정을 활용하거나, JDBC batchUpdateNative Query를 적절히 활용하여 성능을 최적화할 수 있습니다.
  • 데이터 크기, 메모리 사용량, 롤백 비용을 고려하여 배치 크기와 전략을 신중히 설계하세요.

참고

Comments