프로젝트 진행 중에 공공기관 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의 성능 저하 원인
- Hibernate의 변경 감지 (Dirty Checking)
- JPA는 엔티티 변경을 자동 감지하고 UPDATE 처리
- 대량 데이터를 다룰 때 불필요한 메모리 사용 증가 → 성능 저하
- 1차 캐시 (Persistence Context) 사용
- 모든 엔티티를 메모리에 보관 → 대량 데이터 처리 시 OutOfMemory(OOM) 발생 가능
- Batch Insert 미지원 (saveAll()도 한 건씩 INSERT 실행됨)
- MyBatis는 foreach로 한 번에 다수의 데이터를 INSERT 가능
- 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() 적용 🚀
'Programming > Database' 카테고리의 다른 글
[mysql] 날짜 데이터로 요일 조회 쿼리 작성 (0) | 2024.03.20 |
---|---|
[DBeaver] Auto-commit(오토커밋) 설정 해제 방법 (0) | 2022.10.24 |
[MySQL] JOIN 해서 UPDATE하기 (0) | 2022.07.31 |
[MySQL/MariaDB] 문자열 길이(byte수) 구하기 (0) | 2022.05.16 |