JPA N+1 문제, `@BatchSize`로 97% 성능 개선: DdipEvent 엔티티 성능 최적화 사례
🤖 AI 추천
JPA와 Hibernate를 사용하여 애플리케이션을 개발하며 N+1 문제로 인한 성능 저하를 경험했거나, 관련된 최적화 방안을 모색하고 있는 백엔드 개발자에게 이 콘텐츠를 추천합니다. 특히 연관 엔티티가 여러 개 존재하고 순서 보장이 중요한 경우, 배치 로딩을 통한 실질적인 성능 개선 효과를 확인하고 싶은 개발자에게 유용합니다.
🔖 주요 키워드

핵심 기술
본 문서는 JPA의 N+1 문제 발생 시, @BatchSize
어노테이션을 활용한 배치 로딩 기법을 통해 97% 이상의 성능 개선을 달성한 실제 프로젝트 경험을 공유합니다. 특히 여러 List
타입의 컬렉션 연관 관계에서 발생하는 MultipleBagFetchException
오류 해결 및 LAZY
로딩의 이점을 유지하면서 성능을 최적화하는 방안을 제시합니다.
기술적 세부사항
- 문제 상황:
DdipEventEntity
가PhotoEntity
및InteractionEntity
와 1:N 관계로 맺어져 있을 때,LAZY
로딩 적용에도 불구하고 Repository 조회 시 N+1 문제가 발생함. - N+1 문제 발생 원인:
findAll()
로DdipEventEntity
목록 조회 후, 각 엔티티의 연관 컬렉션(photos
,interactions
)에 접근할 때마다 추가적인 SELECT 쿼리가 실행되는 구조.- 총 쿼리 수:
1 + (N × 2)
- 총 쿼리 수:
- EAGER Loading 미고려 이유:
- 불필요한 데이터 로드로 인한 OutOfMemory 및 성능 저하 가능성.
- DB 커넥션 점유 및 네트워크 대역폭 낭비.
- 예측 어려운 쿼리 실행 및 데이터 중복 발생.
- Fetch Join (EntityGraph) 시도와 실패:
@EntityGraph
적용 시cannot simultaneously fetch multiple bags
오류 발생.- 오류 원인: 두 개 이상의
List
타입 컬렉션을 동시에 Fetch Join 할 때 발생하는 Cartesian Product 및 데이터 중복 문제.
- 해결 방안: Batch Loading:
@BatchSize
어노테이션을 사용하여 연관 엔티티를 배치 단위로 조회.List
타입 유지 및 순서 보장 가능.LAZY
로딩의 장점(필요 시점에만 로드) 유지.
- Batch Loading 적용 방법:
- 엔티티 클래스에
@BatchSize(size = 배치_사이즈)
어노테이션 추가. application.properties
또는application.yml
에spring.jpa.properties.hibernate.default_batch_fetch_size=배치_사이즈
설정 (전역 설정).
- 엔티티 클래스에
- 성능 테스트 결과 (1000개 DdipEvent 기준, 배치 사이즈 1000):
- N+1 문제: 평균 응답 시간 19810.50ms, 쿼리 수 2,001개.
- Batch Loading: 평균 응답 시간 468.10ms, 쿼리 수 3개.
- 개선율: 최대 97.6%의 성능 향상.
- 데이터 증가에 따른 영향: 데이터 10배 증가에도 배치 로딩 시 응답 시간 거의 동일 (일관된 성능 유지).
개발 임팩트
- 사용자 경험: 20초 → 0.5초로 40배 빠른 응답 속도 제공.
- 서버 안정성: DB 커넥션 풀 고갈 위험 해소.
- 확장성: 트래픽 증가에도 안정적인 서비스 제공 가능.
- 운영 비용: DB 서버 부하 감소로 인한 하드웨어 비용 절약.
커뮤니티 반응
(원문에 커뮤니티 반응에 대한 직접적인 언급은 없습니다.)
톤앤매너
전반적으로 JPA 및 Hibernate 기반의 백엔드 개발자가 겪을 수 있는 실제적인 성능 이슈와 그 해결 과정을 구체적인 코드 예시와 성능 지표를 통해 명확하게 전달하고 있어, 전문적이고 실용적인 기술 분석 콘텐츠입니다.
📚 관련 자료
Hibernate ORM
Hibernate ORM은 JPA의 핵심 구현체로, N+1 문제 및 `@BatchSize`와 같은 성능 최적화 기능의 동작 원리를 이해하는 데 필수적인 저장소입니다. 문서에서 언급된 `MultipleBagFetchException`과 같은 오류 메시지도 Hibernate 레벨에서 발생합니다.
관련도: 95%
Spring Data JPA
Spring Data JPA는 JPA 리포지토리 추상화를 제공하여 개발자가 JPA 엔티티 관리를 용이하게 하도록 돕습니다. 이 프로젝트에서 사용된 `JpaRepository` 인터페이스 및 `findAll()` 메서드, 그리고 `@EntityGraph`와 같은 기능은 Spring Data JPA를 통해 제공되며, 성능 최적화 설정 또한 Spring Boot 환경에서 통합 관리됩니다.
관련도: 90%
JPA Buddy
주로 IDE 플러그인 형태로 제공되지만, JPA Buddy는 JPA 및 Hibernate 관련 코드 생성, 데이터베이스 매핑, 성능 최적화 팁 등을 제공합니다. N+1 문제 해결을 위한 `@BatchSize`와 같은 설정이나 코드 적용 시 유용한 인사이트를 얻을 수 있는 관련 커뮤니티 프로젝트입니다.
관련도: 70%