join의 N+1 문제
JPA에서 join을 사용해 엔티티를 가져올 경우,
그 엔티티와 연관되어있는 다른 엔티티를 함께 조회하여 가져오지 않는다.
예를 들어, Team 과 Member 엔티티가 존재한다고 가정하자.
select m from Member m join m.team
join 을 써서 Team을 Member와 같이 가지고 올 경우 연관된 엔티티를 함께 조회하지 않기 때문에
총, 두 번의 쿼리가 발생한다.
( 이는 Member들이 모두 동일한 Team을 가질 경우이다 )
총 N + 1 번의 쿼리가 발생한다.
100명의 멤버가 각기 다른 팀을 가지고 있다면 100 + 1 번의 쿼리가 발생한다는 것 이다.
이러한 N+1 문제는 지연로딩과 즉시로딩 둘 다 발생하는 문제이며 성능 상 좋지 못한 영향을 끼친다.
이를 해결하기 위한 방법 중 하나가 JPQL의 fetch join
이다
JPQL의 fetch join이란?
예를 들어
select m from Member m join fetch m.team
이렇게 사용하면 쿼리 한번에 팀과 멤버를 가져올 수 있다.
컬렉션 fetch join
만약, 반대로 팀을 조회할 때 멤버를 함께 조회하고 싶다면?
select t from Team t join fetch t.members where t.name = '도쿤'
이걸 돌려보면 값이 '도쿤'이라는 이름을 가진 팀 하나가 나오는게 아니라 값이 '도쿤'이라는 팀에 소속된 멤버의 갯수만큼 나온다.
왜냐하면 결국엔 DB입장에서 fetch join도 inner join을 사용하기 때문에 중복이 발생한다.
이런 경우 distinct 를 사용하면 중복이 제거된다.
distinct
select distinct t from Team t join fetch t.members
JPQL이 SQL로 변환될 때 distinct를 추가하여 보내주긴 하지만 TEAM JOIN MEMBER를 한 결과 값은 멤버 수 만큼 나오기 때문에 이를 애플리케이션에서 같은 식별자를 가진 엔티티를 골라 중복제거 해준다.
fetch join의 한계
fetch join의 특징
fetch join 정리