[spring] jpql fetch Join

신범철·2023년 9월 22일
0

스프링부트

목록 보기
14/20

사전 지식

경로 표현식

  • .을 통해서 객체 내부를 탐색하는 것을 말한다.
select m.username -> 상태 필드
from Member m
  join m.team t -> 단일 값 연관 필드
  join m.orders o -> 컬렉션 값 연관 필드
where t.name = '팀A'
  • 상태 필드 : 단순히 값을 저장하기 위한 필드
  • 연관 필드
    • 단일 값 연관 필드 : 대상이 단수의 엔티티(@ManyToOne, @OneToOne)
    • 컬렉션 값 연관 필드 : 대상이 컬렉션(@OneToMany, @ManyToMany)

Fetch Join

  • 연관된 엔티티나 컬렉션을 SQL 한번에 함께 조회하는 기능
  • SQL 조인과는 연관 X
  • JPQL에서 성능 최적화를 위한 제공하는 기능
  • join fetch 명령어 사용

엔티티 Fetch Join

  • fetch join 대상이 엔티티(단수)이다.
  • 즉시 로딩처럼 연관된 객체를 함께 조회해서 영속성 컨텍스트 1차 캐시에 저장한다.
  • 하나의 SQL로 가져오는 것이 핵심이다.
    -> (N + 1)문제를 해결하기 위해 많이 사용한다.
/* JPQL -> 회원을 조회하면서 연관된 팀도 함께 조회 (하나의 SQL로!) */
select m from Member m join fetch m.team

/* 실제 수행되는 SQL */
select M.*,T.* from member m
  inner join team t on m.team_id = t.id
// M.*과 T.*은 모든 컬럼을 생략으로 표시한 것 실제로는 이렇게 나오지 X

사용 예시

프젝 예시

컬렉션 Fetch Join

  • fetch join 대상이 컬렉션(복수)이다.
  • 일대다 관계 or 다대다 관계에서 발생
/* JPQL -> 팀을 조회하면서 소속된 멤버들도 함께 조회 (하나의 SQL로!) */
select t from Team t join fetch t.members

/* 실제 수행되는 SQL */
select M.*,T.* from Team t
  inner join Member m on t.id=m.team_id
// M.*과 T.*은 모든 컬럼을 생략으로 표시한 것 실제로는 이렇게 나오지 X
  • 일대다 관계이기 때문에 우리가 받는 team의 결과 리스트에 중복된 결과가 발생한다.
    -> DISTINCT를 통해서 해결할 수 있다.

fetch join과 일반 join

  • 일반 조인 실행시 연관된 엔티티를 함께 조회하지 않는다(지연 로딩하기 때문)
[JPQL]
select t
from Team t join t.members m
where t.name = ‘팀A'

[SQL]
SELECT T.*
FROM TEAM T
INNER JOIN MEMBER M ON T.ID=M.TEAM_ID
WHERE T.NAME = '팀A'

-> Team 엔티티만 조회하고 연관 객체인 member에 대해 조회하지 않는다.

fetch join시 연관된 엔티티를 함께 조회한다.

[JPQL]
select t
from Team t join fetch t.members
where t.name = ‘팀A'

[SQL]
SELECT T.*, M.* // 추가됨
FROM TEAM T
INNER JOIN MEMBER M ON T.ID=M.TEAM_ID
WHERE T.NAME = '팀A'

fetch join 특징과 한계

  • fetch join 대상에는 별칭을 줄 수 없다.
    • 정합성 이슈
  • 둘 이상의 컬렉션은 fetch join을 할 수 없다.
    • 컬렉션의 컬렉션을 타면 위험하다.(일대다대다)
  • 컬렉션을 fetch join하면 페이징 API를 사용할 수 없다.
    • 일대일 / 다대일 같은 단일 값 연관 필드들은 패치조인해도 페이징 가능!

정리

  • 페치 조인은 객체 그래프를 유지할 때 사용하면 효과적
  • 일반조인과 달리 하나의 SQL로 연관된 객체의 정보를 조회한다
    --> 대부분의 N+1 문제를 해결할 수 있음
  • 여러 테이블을 조인해서 엔티티가 가진 모양이 아닌 전혀 다른 결과를 내야하면,
    페치 조인 보다는 일반조인을 사용하고, 필요한 데이터만 조회해 DTO로 받는게 효과적
    --> 최적화에 관한 이야기
profile
https://github.com/beombu

0개의 댓글