Java/Spring

Fetch Join(1) - 개요 및 Join과의 차이점

뽀루피 2024. 8. 20. 20:29

Fetch Join은 N+1문제를 해결하고 성능을 향상시킬 수 있는 기능이다. 오늘은 어떻게 Fetch Join이 성능을 향상시키는지 알아보자.

 

우선 Fetch Join에 대해서 정리하고 가야할 것이 있는데 Fetch Join은 DB에서 지원하는 기능이 아닌 JPA의 JPQL에서 제공하는 기능이다. 그렇다면 Join에서 어떤 것이 부족해서 Fetch Join이라는 함수를 따로 만들었을까? 이는 객체와 테이블을 맵핑하려는 데에서 파생된 문제에서 시작되었다.

 

아래와 같은 Member와 Team이라는 테이블이 있다고 하자. 

Member / Team : 일대다 관계

 

Member는 Team과 다대일의 관계를 가지고 있다. 만약 Member 전체를 조회하는 JPQL을 짠다면 Team의 ID, 이름, 나이가 영속성 컨텍스트에 저장되고 Team 엔티티는 조회하지 않으며 프록시 객체 상태로 저장될 것이다( 지연 로딩으로 가정 ). 그리고 이 연관된 Team 엔티티가 비지니스 로직에서 사용될 때마다 조회 쿼리가 나간다( N+1문제 ).

 

이 문제를 해결하기 위해 Fetch Join이 생긴 것이다. Fetch Join을 사용하면 조회 주체인 Team 엔티티 뿐만 아니라 연관된 객체를 전부 불러온다.

 

Fetch Join 결과 쿼리. member 속성과 team 속성 모두 가져오는 모습

 

 

Join vs Fetch Join

"그건 Join으로도 풀 수 있지 않나요?"

아니다. 아래의 예시를 보자.

 

Inner Join 결과 쿼리. team 속성만 가져오는 모습

 

예상과 다르게 Join을 사용했을 때는 Team 엔티티만을 불러온다. JPQL은 조회하는 주체가 되는 Entity만 조회하여 영속화하기 때문이다. 그렇다면 Team과 Member 둘 다 조회를 한다면 어떨까?

 

Team, Member 엔티티를 조회하는 Inner Join 쿼리 결과.

 

Team 엔티티와 Member 엔티티를 모두 정상적으로 가져오는 것처럼 보인다. 하지만 여기엔 문제가 있으니 Team과 Member를 각각 불러왔기 때문에 Team에 있는 List<Member>가 초기화되지 않는다. 이렇게되면 Team의 members 컬렉션에 접근할 때 지연 로딩이 발생하고, 추가적인 쿼리가 필요하게 될 수 있다.

 

결론적으로 Fetch Join은 조회하는 주체 Entity 뿐만 아니라 연관되는 엔티티도 영속성 컨텍스트에 저장하고, 서로를 가리키는 참조 또한 설정된다

그러니까 JPQL에서 제공하는 Fetch Join을 사용하자!