내 맴
[JPA] N+1 문제 발생 원인과 해결 본문
728x90
✅ 정리
N+1 문제는 하나의 쿼리(N) 실행 후 연관된 데이터를 위해 추가로 N개의 쿼리가 발생하는 현상
연관 관계가 있는 엔티티 조회 시, 지연 로딩(fetch = LAZY)으로 인해 반복적으로 추가 쿼리 발생
→ 성능 저하 유발
✅ 상세 정리
1. 개념
- N+1 문제:
특정 엔티티 리스트를 조회(N)한 후, 각 엔티티의 연관 객체를 지연 로딩하면서 추가 쿼리(N) 발생 → 총 N+1개의 쿼리 실행됨.
2. 내부 동작
- JPA에서 연관 관계는 기본적으로 LAZY로 설정됨.
- 루트 엔티티 조회 시에는 1개의 쿼리만 실행됨.
- 연관된 엔티티 접근 시점에 각각 쿼리가 발생하며, 루프를 돌며 연속 접근 시 N개의 추가 쿼리 실행됨.
3. 발생 예시
List<Team> teams = teamRepository.findAll(); // 1개의 쿼리 (N)
for (Team team : teams) {
System.out.println(team.getMembers()); // 팀 수만큼 추가 쿼리 (N번)
}
4. 해결 방법
- Fetch Join 사용
연관된 엔티티를 한 번에 함께 조회 - EntityGraph 사용
JPQL이 아닌 메서드 쿼리에서 fetch 전략 설정 - BatchSize 설정
IN 절을 활용해 한 번에 여러 개를 조회하여 쿼리 수 줄임
5. 예외사항 및 주의점
- Fetch Join 시에는 페이징 처리 제한 존재 (@OneToMany 관계에서 사용 시 주의)
- 필요 없는 연관 객체까지 모두 로딩하면 과도한 메모리 사용 유발
✅ Java 코드 예시
1. N+1 문제 발생 코드
public List<Team> getTeams() {
return entityManager.createQuery("SELECT t FROM Team t", Team.class)
.getResultList(); // 이후 getMembers() 접근 시 N개의 쿼리 추가 실행
}
2. Fetch Join으로 해결
public List<Team> getTeamsWithMembers() {
return entityManager.createQuery(
"SELECT t FROM Team t JOIN FETCH t.members", Team.class)
.getResultList(); // 단 1개의 쿼리로 팀과 멤버 함께 조회
}
728x90
'개발 공부 > Database & JPA' 카테고리의 다른 글
[JPA] @OneToMany와 @ManyToOne의 차이 (0) | 2025.04.09 |
---|