25.04.02 TIL Fetch Join

신성훈·2025년 4월 2일

TIL

목록 보기
160/162

1. Fetch Join이란?

  • 연관된 엔티티를 함께 조회하는 JPQL의 기능이다.
  • JPA는 연관된 엔티티를 지연 로딩(LAZY)으로 설정하는 경우가 많은데 이때 연관 데이터를 필요할 때마다 별도 쿼리로 가져오게 된다.
    이로 인해 N+1 문제가 발생한다.

N+1 문제란?

  • 1개의 쿼리로 N개의 엔티티를 가져온 후 각 엔티티에 대해 추가 쿼리가 실행되어 총 N+1번의 쿼리가 발생하는 현상이다.

2. Fetch Join 사용 예시

일반 Join (지연 로딩)

SELECT o FROM Order o JOIN o.member m
  • Order는 한 번에 가져오지만 Member는 프록시로 로딩되고 실제 접근 시 추가 쿼리 발생 (N+1 문제 가능성 있음)

Fetch Join (즉시 로딩)

SELECT o FROM Order o JOIN FETCH o.member
  • Order와 연관된 Member하나의 쿼리로 함께 조회한다.
  • fetch 키워드가 핵심! → 이걸 쓰면 JPA가 즉시 연관 객체도 함께 조회함

3. 실무에서의 예시

// Entity 관계
class Order {
    @ManyToOne(fetch = FetchType.LAZY)
    private Member member;
}

@Query("SELECT o FROM Order o JOIN FETCH o.member WHERE o.status = :status")
List<Order> findAllWithMemberByStatus(@Param("status") OrderStatus status);
  • OrderMemberManyToOne 관계이며 지연 로딩이다.
  • 위 쿼리는 Order와 연관된 Member를 한 번의 쿼리로 모두 로딩한다.
  • 결과적으로 SQL은 JOIN 문 하나만 실행되고, 이후 member에 접근할 때 추가 쿼리가 발생하지 않는다.

4. 주의사항

  • 컬렉션(fetch join on @OneToMany 등)은 페이징 처리 시 문제 발생
    → 데이터가 뻥튀기되어 페이징이 메모리에서 처리되므로 실제 운영에서는 주의가 필요
  • fetch join은 반드시 JPQL에서 사용 가능 SQL에는 없는 기능이다.
  • 여러 fetch join을 동시에 사용할 경우(다중 컬렉션) → JPA에서는 불가능하거나 비효율적

5. 마무리

Fetch join은 JPA에서 성능 최적화를 위해 거의 필수적으로 사용하는 기능이다.
N+1 문제 해결에 강력한 효과를 발휘한다. 하지만 무조건 fetch join을 남용하면 오히려 성능이 저하될 수 있기 때문에 언제 사용해야 하는지 판단할 수 있는 눈이 중요하다고 느꼈다.
쿼리를 작성할 때 연관 객체가 사용되는지 미리 파악해서 fetch join을 고려하는 습관을 들여야겠다.
복잡한 조회나 컬렉션 조인이 필요한 경우에는 QueryDSL 또는 DTO로 변환하는 방식을 고민해야겠다고 느꼈다.

profile
조급해하지 말고, 흐름을 만들고, 기록하면서 쌓아가자.

0개의 댓글