반응형
- JPA에서 연관관계가 LAZY(지연 로딩)일 때 자주 발생
- 예시: Team과 Member 관계 (1:N)
List<Team> teams = em.createQuery("select t from Team t", Team.class)
.getResultList();
for (Team team : teams) {
System.out.println(team.getMembers().size());
}
실행 쿼리
- select * from team → 팀 목록(N개)
- 각 팀의 getMembers() 접근할 때마다:
- select * from member where team_id=? → 팀마다 N번 실행
최종적으로 1 + N번의 쿼리 발생 = N+1 문제
N+1 문제 해결 방법
1. Fetch Join (가장 많이 쓰는 방법)
- JPQL에서 연관된 엔티티를 한 번에 함께 조회
// 팀 + 멤버를 한 번에 조회
List<Team> teams = em.createQuery(
"select t from Team t join fetch t.members", Team.class)
.getResultList();
실행 쿼리:
select t.*, m.*
from team t
join member m on t.id = m.team_id
- 장점: 한 번에 가져와서 N+1 문제 해소
- 단점: 조인 때문에 중복 데이터가 생길 수 있음 → DISTINCT 필요할 수도
2. EntityGraph (Spring Data JPA에서 자주 씀)
- 어노테이션으로 Fetch Join 효과를 줌
@EntityGraph(attributePaths = "members")
@Query("select t from Team t")
List<Team> findAllWithMembers();
내부적으로 Fetch Join을 써서 한 번에 조회
3. Batch Fetching (hibernate.default_batch_fetch_size)
- 지연 로딩을 쓰되, 한 번에 여러 건을 IN 쿼리로 묶어서 가져오기
- Hibernate 설정:
spring.jpa.properties.hibernate.default_batch_fetch_size=100
- 실행 쿼리 예시
select * from member where team_id in (1, 2, 3, ...);
즉, 팀을 10개 조회하면 각 팀 멤버를 하나씩 따로 안 불러오고,
한 번의 IN 쿼리로 최대 100개씩 모아서 가져옴
반응형
'Spring Boot > JPA(Java Persistence API)' 카테고리의 다른 글
영속성 컨텍스트 (0) | 2025.08.28 |
---|---|
쿼리 방법(JPQL/Criteria) (1) | 2025.08.28 |
매핑 규칙(어노테이션) (1) | 2025.08.28 |
EntityManager API (0) | 2025.08.28 |