해당 포스팅은 김영한님의 Fetch Join 관련 강의를 들으면서 위키를 작성하듯이 작성한 글입니다~~ 가볍게 봐주시길 바랍니다.
- JPQL에서 성능 최적화를 위해 제공하는 기능
- 연관된 엔티티나 컬렉션을 SQL 한번에 함께 조회하는 기능!!
- join fetch는 Inner Join과 같은 역할을 한다.
ex)
select m from Member m join fetch m.team =
select M.*, T.* From Member M INNER JOIN TEAM T ON M.TEAM_ID = T.ID
문제
즉시로딩을 하든, 지연로딩을 하든 N+1 문제는 무조건 발생!!
- 팀과 멤버 관계에서 멤버 조회시 팀의 이름도 알고 싶을 때
- 멤버조회 (1) + 각 멤버들의 팀 조회(N) -> N+1 문제
- 최악의 경우 N+1, 팀이 공통되는 경우, 영속성 컨텍스트가 1차 캐시 역할을 한다.
- fetch join - 프록시 객체가 담기지 않음!! 실제 엔티티가 영속성 컨텍스트에 올라와 잇음!!!
- 지연로딩보다 fetch join이 우선시!!
주의점
컬렉션 페치조인? - 일대다 관계, 컬렉션 페치 조인
- 디비입장에서 일대다 조회시 데이터가 뻥튀기 되어 조회된다.
memberA - teamA
memberB - teamA
memberC - teamB
select t from Team t join fetch t.members

다음과 같이 조회 - ID(PK)가 동일한 튜플이 조회된다.!!
- SQL의 DISTINCT를 통해 중복 제거 - 튜플의 값이 완전히 똑같아야 중복 제거가 됨.
- JPQL의 DISTINCT 2가지 기능 - SQL에 DISTINCT 추가, 애플리케이션에서 중복 엔티티 제거 - 같은 식별자를 가진 Team 엔티티를 제거
select distinct t from Team t join fetch t.members
페치 조인 vs 일반 조인
- select t from Team t join fetch t.members
실제 join되는 데이터는 가져오지 않는다. N+1 문제 발생!!
연관된 엔티티를 함께 조회하지 않음! Select 절에 지정한 엔티티만 조회
- select t from Team t join t.members
객체 그래프를 SQL 한방에 조회
페치 조인의 한계
- 페치조인 대상에는 별칭을 줄 수 없음!! where문을 쓰면 위험함.
- 연관관계 엔티티에 대한 조건을 줘서 거르면서 조회하면 안됨..!! 원래 데이터가 5개인데 데이터가 3개밖에 안나옴. JPA는 페치 조인시 전체를 다 가져와야함.
- 객체 그래프는 거르면서 데이터를 조회하면 좋지않음..! 데이터의 정합성과 JPA 사상과 맞지 않음!
- 둘 이상의 컬렉션은 페치 조인을 할 수 없음! 일대다대다 ~~~ -> 데이터 정합성이 안맞음, 데이터가 뻥치기 되어 데이터 갯수가 곱의 곱이 될 수 있다.
- 컬렉션을 페치 조인하면 페이징 API(setFirstResult, setMaxResults)를 사용할 수 없음. -> 데이터 뻥튀기를 페이징을 한다 ?? 안된다. 일대다 페치 조인 데이터 뻥튀기 팀에 속한 멤버가 잘린다.!! -> 페이징 처리가 안되고 모든 데이터를 가져옴!!
-> 뒤집어서 다대일로 조회하여 페이징 방향을 변경
-> @BatchSize(size=1000)
-> global 세팅 hibernate.default_batch_fetch_size value=1000 -> 1000이하의 적절한 수
-> 쿼리가 N+1이 아닌 테이블 수에 맞출수 있음??

-
연관된 엔티티들을 SQL로 한번에 조회 - 성능 최적화
-
Fetch Join은 엔티티에 직접 적용하는 로딩 전략보다 우선권을 가짐.
-
모든 로딩전략은 모두 지연 로딩
-
최적화가 필요한 곳은 페치 조인 적용 !!
-
모든 것을 페치 조인으로 해결할 수 없음
-
페치 조인은 객체 그래프를 유지할 때 사용하면 효과적
-
여러 테이블을 조인해서 엔티티가 가진 모양이 아닌 전혀 다른 결과를 내야 하면, 페치 조인 보다는 일반 조인을 사용하고 필요한 데이터들만 조회해서 DTO로 반환하는 것이 효과적
-
엔티티 조회 (fetch join) 그대로 사용
-
fetch join해서 애플리케이션에서 dto로 변환해서 사용
-
뉴 오퍼레이션에서 DTO로 스위칭해서 가져온다