SELECT o FROM Order o JOIN o.member m
Order는 한 번에 가져오지만 Member는 프록시로 로딩되고 실제 접근 시 추가 쿼리 발생 (N+1 문제 가능성 있음)SELECT o FROM Order o JOIN FETCH o.member
Order와 연관된 Member를 하나의 쿼리로 함께 조회한다.fetch 키워드가 핵심! → 이걸 쓰면 JPA가 즉시 연관 객체도 함께 조회함// 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);
Order와 Member는 ManyToOne 관계이며 지연 로딩이다.Fetch join은 JPA에서 성능 최적화를 위해 거의 필수적으로 사용하는 기능이다.
N+1 문제 해결에 강력한 효과를 발휘한다. 하지만 무조건 fetch join을 남용하면 오히려 성능이 저하될 수 있기 때문에 언제 사용해야 하는지 판단할 수 있는 눈이 중요하다고 느꼈다.
쿼리를 작성할 때 연관 객체가 사용되는지 미리 파악해서 fetch join을 고려하는 습관을 들여야겠다.
복잡한 조회나 컬렉션 조인이 필요한 경우에는 QueryDSL 또는 DTO로 변환하는 방식을 고민해야겠다고 느꼈다.