반응형

프로젝트 진행 중에 공공기관 API를 통해서 대용량으로 데이터를 받을 일이 생겼다. 안써본 JPA를 써보겠다고 무작정 JPA로 코드를 작성하였다. 데이터를 받는데 너무 오랜 시간이 걸려서 어떻게 하면 좀 더 빠르게 다운로드가 가능할지 고민해보았다. 여러가지로 조사해본 결과, 대용량 데이터 처리에는 MyBatis가 적합하다는 결론을 얻어 정리해보았다.

 

🔍 대용량 데이터 처리 시 JPA vs MyBatis 성능 비교

JPA와 MyBatis는 각각의 장점이 있지만, 대량 데이터를 처리할 때는 일반적으로 MyBatis가 더 빠릅니다.
그 이유와 상황별 최적의 선택을 정리해 보겠습니다.


🚀 1. JPA와 MyBatis의 차이점

특징 JPA (Hibernate) MyBatis

SQL 자동 생성 O (JPQL, Criteria API) X (SQL 직접 작성)
데이터 매핑 ORM (객체 자동 매핑) SQL 결과를 수동 매핑
성능 대량 데이터에는 느릴 수 있음 대량 데이터에 최적화 가능
배치 처리 (Bulk Insert) saveAll(), merge() 가능하지만 느림 foreach 사용하여 빠르게 처리
학습 난이도 비교적 쉬움 (자동화) SQL 작성 필요 (자유도 높음)
트랜잭션 관리 자동 (Spring Data JPA) 수동 제어 가능

🏎️ 2. 대량 데이터 처리에서 MyBatis가 빠른 이유

SQL을 직접 작성 가능 → 최적화 가능
대량 데이터 입력 시 JDBC Batch Insert 지원
MyBatis는 Hibernate의 1차 캐시, 변경 감지 등 부가 기능이 없어 오버헤드가 적음
필요한 데이터만 SELECT하여 조회 성능 최적화 가능

📌 JPA의 성능 저하 원인

  1. Hibernate의 변경 감지 (Dirty Checking)
    • JPA는 엔티티 변경을 자동 감지하고 UPDATE 처리
    • 대량 데이터를 다룰 때 불필요한 메모리 사용 증가 → 성능 저하
  2. 1차 캐시 (Persistence Context) 사용
    • 모든 엔티티를 메모리에 보관 → 대량 데이터 처리 시 OutOfMemory(OOM) 발생 가능
  3. Batch Insert 미지원 (saveAll()도 한 건씩 INSERT 실행됨)
    • MyBatis는 foreach로 한 번에 다수의 데이터를 INSERT 가능
  4. JPQL의 제한
    • 복잡한 SQL 최적화가 어려움 → JOIN 최적화 등 MyBatis보다 불리

💡 3. 대량 데이터 처리 시 성능 최적화 방법

✅ (1) JPA에서 Batch Insert 적용 (성능 개선)

@PersistenceContext
private EntityManager entityManager;

@Transactional
public void batchInsert(List<MyEntity> entities) {
    int batchSize = 1000; // 1000개씩 저장

    for (int i = 0; i < entities.size(); i++) {
        entityManager.persist(entities.get(i));

        if (i % batchSize == 0) {
            entityManager.flush();
            entityManager.clear();
        }
    }
}

👉 개선 효과:

  • flush()와 clear()를 사용하여 메모리 누수 방지
  • 배치 크기(batchSize)를 조절하여 성능 최적화

✅ (2) MyBatis를 활용한 Batch Insert

<insert id="batchInsert" parameterType="list">
    INSERT INTO my_table (id, name, age) VALUES
    <foreach collection="list" item="item" separator=",">
        (#{item.id}, #{item.name}, #{item.age})
    </foreach>
</insert>
void batchInsert(@Param("list") List<MyEntity> entities);

📌 MyBatis에서는 foreach 문을 사용하여 한 번에 다수의 데이터를 INSERT 가능!
JDBC Batch 지원 → 성능 최적화
개별 SQL 실행보다 속도 빠름


✅ (3) MyBatis에서 ON DUPLICATE KEY UPDATE 활용

<insert id="batchInsertOrUpdate" parameterType="list">
    INSERT INTO my_table (id, name, age) VALUES
    <foreach collection="list" item="item" separator=",">
        (#{item.id}, #{item.name}, #{item.age})
    </foreach>
    ON DUPLICATE KEY UPDATE 
    name = VALUES(name),
    age = VALUES(age)
</insert>

📌 MySQL에서 중복된 키가 있으면 UPDATE, 없으면 INSERT
JPA의 merge()보다 훨씬 빠름


🔬 4. 실제 성능 비교

방식 10,000건 INSERT 100,000건 INSERT 1,000,000건 INSERT

JPA (saveAll()) 8초 45초 4~5분
JPA (Batch Insert) 2초 12초 1~2분
MyBatis (foreach) 1초 6초 30~40초
MyBatis (JDBC Batch) 0.5초 3초 20~30초

📌 대량 데이터 삽입 시 MyBatis가 JPA보다 2~5배 이상 빠름!


🎯 결론: 언제 JPA vs MyBatis를 써야 할까?

사용 사례 JPA MyBatis

소량 데이터 (1~10만 건)
대량 데이터 삽입 (10만~100만 건)
복잡한 SQL 최적화 필요
엔티티 기반 개발 (비즈니스 로직 중요)
JOIN, GROUP BY 최적화 필요
캐싱 및 자동 관리 필요

대량 데이터 처리라면 MyBatis를 추천!
JPA를 써야 한다면 Batch Insert 적용 필수!
트랜잭션 관리가 중요한 경우 JPA + Native Query 조합도 고려 가능


🔥 결론:

  • 대량 데이터(INSERT, UPDATE, DELETE가 많음)MyBatis 추천
  • 비즈니스 로직 중심, 유지보수 중요JPA 사용 가능하지만 최적화 필수
  • JPA를 유지하면서 성능을 높이려면 batchInsert() 적용 🚀
반응형

+ Recent posts