fetch join은 Spring Boot + JPA (Hibernate) 환경에서 지연 로딩(LAZY) 관계의 데이터를 한 번의 쿼리로 함께 조회할 때 사용하는 방법

JPA에는 엔티티에 관계를 맵핑할 때 지연 로딩과 즉시 로딩 설정할 수 있다.
일반 Join : 연관 Entity에 Join을 걸어도 실제 쿼리에서 SELECT 하는 Entity는 오직 JPQL에서 조회하는 주체가 되는 Entity만 조회하여 영속화한다.
Fetch Join : 조회의 주체가 되는 Entity 이외에 Fetch Join이 걸린 연관 Entity도 함께 SELECT 하여 모두 영속화

Member Entity와 Team Entity가 @ManyToOne 일 때 Entity 클래스에 서로의 관계를 표시해 준다.

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@ToString
public class Member {
    @Id
    @GeneratedValue
    @Column(name = "member_id")
    private Long id;
    private String username;
    private int age;
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "team_id")
    @ToString.Exclude
    private Team team;
}


Fetch Join 을 사용해야 하는 상황
1. @ManyToOne, @OneToOne 연관 관계의 객체가 반복적으로 로딩될 때
   @Query("SELECT m FROM Member m JOIN FETCH m.team")
   List<Member> findAll();  // N+1 문제 해결

2. JPQL 또는 QueryDSL로 다대일 관계를 한 번에 조회하고자 할 때
   @ManyToOne, @OneToOne 관계는 fetch join으로 쉽게 한 쿼리에 묶을 수 있음

Fetch Join을 사용하면 안 되는 경우
1. 컬렉션(@OneToMany, @ManyToMany)에 페치 조인을 사용하면서 페이징이 필요한 경우
   JPA는 fetch join이 있는 경우 Pageable 정보를 무시하거나, 메모리에서 잘라내기 때문에 성능 이슈 발생
   @BatchSize 또는 별도 쿼리

2. 복수 개의 컬렉션을 동시에 Fetch Join 할 때
   @Query("SELECT d FROM Department d JOIN FETCH d.employees JOIN FETCH d.projects") 
   여러 컬렉션이 곱해져서 결과가 기하급수적으로 커질 수 있음
   해결 방법: 컬렉션 하나만 fetch join, 나머지는 batch fetch 사용

728x90
블로그 이미지

Link2Me

,