20만 건의 데이터를 읽어와 데이터베이스에 저장하는 로직을 구현하면서, JPA의 saveAll() 방식과 JDBC를 활용한 Bulk Insert 방식을 비교하며 겪었던 차이를 중심으로 작성한 글이다.
대량 데이터 저장 기능은 시스템 성능에 직접적인 영향을 미치기 때문에, 효율적인 쿼리 실행 방식이 필수적이다. 성능 최적화를 목표로 두 가지 방식의 장단점을 분석하고, 그 차이를 정리했다.
JPA vs JDBC
- 스프링 데이터 JDBC 특징
- JDBC 위에 얇은 추상화 계층을 제공, SQL 직접 제어가 가능.
- 설정이 간단하며 성능 최적화가 중요한 애플리케이션에 적합.
- 개발자가 SQL을 직접 작성하여 데이터베이스 작업을 세밀하게 제어 가능.
JDBC는 Java에서 데이터베이스와 상호작용하기 위한 표준 API입니다. 이를 통해 Java 애플리케이션은 다양한 관계형 데이터베이스에서 데이터를 읽고 쓰는 작업을 수행할 수 있습니다.
@Repository
public class MyRepository {
@Autowired
private JdbcTemplate jdbcTemplate;
public List<MyEntity> findAll() {
return jdbcTemplate.query("SELECT * FROM my_table", new BeanPropertyRowMapper<>(MyEntity.class));
}
}
- JPA 특징
- ORM 기반 자바 표준으로, 객체와 데이터베이스 테이블 간의 자동 매핑 지원.
- 복잡한 데이터베이스 작업과 객체 관계 매핑을 자동화하여 개발 속도와 유지보수성을 높임.
- 객체 지향적 프로그래밍 방식에 적합.
@Entity public class MyEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; } public interface MyRepository extends JpaRepository<MyEntity, Long> { }
- 선택 기준
- 스프링 데이터 JDBC: 성능 최적화와 SQL 제어가 중요한 경우, 단순한 데이터베이스 구조에 적합.
- JPA: 객체 지향적 접근이 필요하거나, 복잡한 데이터 관계를 처리해야 하는 대규모 프로젝트에 적합.
JPA saveAll() vs JDBC Batch Insert 방식 비교와 성능 최적화
- JPA saveAll() 방식의 문제점
- JPA의 saveAll()은 편리하게 다수의 엔터티를 저장할 수 있는 메서드
- 그러나 내부적으로 다음과 같은 한계가 존재
- saveAll()은 입력된 엔터티 리스트의 크기만큼 개별 Insert 쿼리를 생성
- 예를 들어, 20만 건의 데이터를 저장하면 20만 개의 Insert 쿼리가 발생하며, 데이터베이스 접근 횟수 역시 동일
- 이는 데이터베이스 연결 자원을 많이 소모하고 성능 병목을 유발
- JDBC를 활용한 Batch Insert 방식
- JDBC의 batchUpdate를 활용하면 대량의 데이터를 효율적으로 삽입할 수 있음
- Batch 처리로 쿼리 최소화
- 하나의 SQL 템플릿을 사용하여 다수의 데이터를 한 번에 삽입
- 예: 20만 건의 데이터를 1,000건씩 배치로 나누면 약 200번의 Insert 쿼리로 처리 가능.
- 이는 JPA의 saveAll() 대비 데이터베이스 접근 횟수를 획기적으로 줄여줌
- 구현 예시
@Repository @RequiredArgsConstructor public class PostCustomRepositoryImpl implements PostCustomRepository { private final JdbcTemplate jdbcTemplate; // 게시글 목록 저장, BULK INSERT 방식으로 처리 @Transactional public void saveAllByJdbcTemplate(List<Post> posts) { String sql = "INSERT INTO post (title, content, name, views) VALUES (?, ?, ?, ?)"; jdbcTemplate.batchUpdate(sql, posts, 1000, (ps, post) -> { ps.setString(1, post.getTitle()); ps.setString(2, post.getContent()); ps.setString(3, post.getName()); ps.setLong(4, post.getViews()); }); } }
참고
JPA Batch Insert API 성능 개선기 (GenerationType.IDENTITY의 한계점)
JPA Batch Insert API 성능 개선기 (GenerationType.IDENTITY의 한계점) 개요안녕하세요? 오늘은 성능적으로 문제가 있던 API의 처리속도를 간단한 해결방법을 통하여 96%가량 개선한 사례를 적어보려 합
sandcastle.tistory.com
[SpringBoot] Bulk Insert 알아보기 (Insert 쿼리 최적화)
모든 성능 개선은 SQL 개선으로부터 시작된다 - BlackBean99 -
velog.io
'Dev > SpringBoot' 카테고리의 다른 글
인기 게시글 조회 성능 최적화 (0) | 2025.02.11 |
---|---|
동시성 제어 (0) | 2025.02.11 |
Cotato 10th 백엔드 네트워킹 회고 1 (1) | 2025.02.10 |
default_batch_fetch_size (0) | 2025.02.10 |
@Transient (0) | 2025.02.10 |