N+1 문제란

1번의 쿼리로 N개의 엔티티를 조회한 뒤, 연관 엔티티를 로딩할 때 N번의 추가 쿼리가 발생하는 현상입니다. 연관관계가 LAZY로 설정된 경우 반복문 안에서 연관 필드에 접근할 때 주로 나타납니다.

원인 분석

JPA의 기본 fetch 전략은 컬렉션 연관관계에서 LAZY입니다. 프록시 객체로 초기화된 연관 엔티티는 실제 접근 시점에 SELECT가 발생합니다. 루프 안에서 접근하면 N번의 쿼리가 추가됩니다.

Fetch Join으로 해결

JPQL에서 JOIN FETCH를 사용하면 연관 엔티티를 한 번의 쿼리로 함께 로딩합니다. 페이지네이션과 함께 사용 시 메모리 페이징 경고가 발생할 수 있습니다.

@Query("SELECT o FROM Order o JOIN FETCH o.member")
List<Order> findAllWithMember();

EntityGraph 활용

@EntityGraph를 사용하면 JPQL 없이 fetch 전략을 오버라이드할 수 있습니다. 특정 연관관계만 즉시 로딩하도록 선택적으로 적용 가능합니다.

BatchSize 설정

컬렉션 연관관계에서 Fetch Join을 사용하면 중복 데이터가 발생할 수 있습니다. @BatchSize를 적용하면 IN 절로 N개를 한 번에 조회합니다.