1. 개요
JPA 프로젝트를 진행하며 한가지 의문이 들었다. 'fetch = FetchType.EAGER' 와 'fetch-join (@Entity-graph)' 둘 다 진짜 객체를 한번에 조회할 수 있도록 하는 것인데.. 왜 'fetch-join (@Entity-graph)'의 성능이 더 좋은 것일까? 이 의문을 풀기 위해 공부한 내용을 포스팅 하려한다.
2. 공통점
두 개념은 모두 가짜 객체를 사용하지 않고, 엔티티를 조회할때 모두 진짜 객체로 가져와 한꺼번에 조회할 수 있도록 하는 기능을 가진다.
3. 차이점
이 둘의 차이점이 이번 포스팅의 핵심 내용이 될 것이다. 차이점을 하나하나 살펴보자.
3-1. fetch = FetchType.EAGER
이 코드는 엔티티 클래스 내부의 연관관계 어노테이션 중 하나의 속성으로 사용된다.
@ManyToOne(fetch = FetchType.EAGER) // default (@ManyToOne, @OneToOne)
@ManyToOne(fetch = FetchType.LAZY) // 지연로딩, default (@OneToMany, @ManyToMany)
특히 @ManyToOne 다대일 관계 어노테이션에 쓰이는 속성으로, 단방향 관계에서 사용하는 어노테이션이다.
예를 들어 회원(Member)과 팀(Team)의 관계가 있다고 했을때, 회원만을 조회하고 싶은데, 팀이라는 불필요한 엔티티가 조회된다면, 규모가 큰 프로젝트에서는 큰 성능저하로 이어질 수 있다. ( @ManyToOne(fetch = FetchType.EAGER) )
반대로, 팀을 조회할때 그에 속한 회원들은 엄청 많을 수도 있으므로 (성능저하 확률 ↑) @OneToMany(fetch = FetchType.LAZY) 가 기본값인 것이다.
@ManyToOne(fetch = FetchType.LAZY) 로 설정하면, 자신의 엔티티(Member) 멤버변수 (컬럼) ROW 데이터만 조회하고, 나중에 필요할때 Team 엔티티의 데이터를 조회할 수 있다.
하지만, 지연로딩은 <<N+1 문제>>라는 단점이 존재하는데, 예를 들어 10명의 회원 데이터를 SELECT 한다고 했을때, 가짜객체였던 Team 엔티티를 실제로 조회하게 되었을때, 또 다시 10번의 SELECT 쿼리가 실행되는 문제이다. 이는 성능저하로 이어진다.
3-2. fetch join (@EntityGraph)
이러한 <<N+1 문제>>를 보완하기 위해 나온 개념이 바로 fetch join(@EntityGraph)이다. 사용 위치는 JPA Hibernate 구현체 내부 (레포지토리 클래스 내부)의 JPQL 및 메소드 상단 @EntityGraph 어노테이션으로 사용한다. fetch join과 @EntityGraph는 동일한 개념이며, JPQL에 fetch join을 명시하고 싶지 않을 때 @EntityGraph 어노테이션을 사용한다. (가독성 ↑)
@Query("SELECT m" +
" FROM Member m" +
" LEFT JOIN FETCH m.team")
List<Member> findMemberFetchJoin();
@Override // 상위 인터페이스 JPARepository의 findAll 메서드를 재정의
@EntityGraph(attributePaths = {"team"}) // attributePaths에 명시한 엔티티만 즉시 조회
List<Member> findAll();
4. 정리
◆ fetch = FetchType.EAGER와 fetch join (@EntityGraph)는 연관관계 엔티티를 한번에 즉시 조회하는 것은 동일하다.
◆ fetch = FetchType.EAGER는 엔티티 클래스 내부 연관관계 어노테이션의 속성으로 존재하며 불필요한 연관 엔티티까지 모두 조회되므로, 성능저하가 일어날 수 있다.
◆ fetch join (@EntityGraph)은 JPA 구현체 내부의 JPQL 및 메소드 상단 @EntityGraph로 존재하며, 해당 기능에 필요한 연관 관계 엔티티만 지정하여 조회할 수 있어, 지연로딩의 장점은 물론, 단점인 <<N+1 문제>>를 보완한 기능이다.
긴 글 읽어주셔서 감사합니다. 틀린 내용이나, 보완이 필요한 내용이 있다면 언제든 댓글 달아주시면 감사하겠습니다!