JPQL에서 성능 최적화를 위해 제공하는 기능
연관된 엔티티나 컬렉션을 SQL 한번에 함께 조회하는 기능
명령어
[left] join fetch
페치 조인을 사용할 때만 연관된 엔티티도 함께 조회(즉시로딩 - 엔티티에 직접 적용하는 글로벌 로딩 전략보다 우선함)
이 기능이 너무 중요하다. 기존 지연로딩에서 발생했던 문제들을 대부분 해결해준다.
페치 조인은 객체 그래프를 SQL 한번에 조회하는 개념
ToOne(ManyToOne, OneToOne) 연관관계를 페치조인할때의 경우
해당 엔티티와 관련된 엔티티를 함께 조회해 준다
EX)
MEMBER - {1,'han1', 3(FK)}, {2,'han2', 3(FK)}, {3,'han3',4(FK)}
TEAM - {3,'team1'}, {4,'team2'} 일때
select m from member m join fetch m.team
(JPQL)의 결과
member_id | username | team_id(FK) | team_id | team_name |
---|---|---|---|---|
1 | han1 | 3 | 3 | team1 |
2 | han2 | 3 | 3 | team1 |
3 | han3 | 4 | 4 | team2 |
-> 기존 멤버의 정보에서 team의 정보까지 함께 조회됐다.
SQL에서는
select m.*, t.* from member m join team t on m.team_id=t.team_id
로 입력된다.
ToMany 연관관계를 페치조인할때의 경우
해당 엔티티와 연관된 컬렉션을 함께 조회해준다.
select t from team t join fetch t.members
(JPQL)의 결과
SQL에서는 select t.*, m.* from team t join member m on m.team_id=t.team_id
team_id | team_name | member_id | username | team_id(FK) |
---|---|---|---|---|
3 | team1 | 1 | han1 | 3 |
3 | team1 | 2 | han2 | 3 |
4 | team2 | 3 | han3 | 4 |
기존 엔티티(TEAM)의 데이터가 뻥튀기된다.
페치조인없이 team의 정보만 조회했을 경우 team1, team2 두개의 데이터만 조회되지만, t.members 컬렉션을 페치 조인해서 team의 데이터가 뻥튀기 되었다.
뻥튀기되는 이유는 team과 member의 연관관계가 OneToMany이기 때문
-> 하나의 팀을 골랐을때 여러명의 멤버가 나올 수 있다
JPQL의 페치조인은 그냥 연관관계가 있는 필드(지연로딩)에 값을 넣어주는 일만 할뿐
(결과는 SQL의 기본 조인과 같다)
SQL의 DISTINCT는 중복된 결과를 제거하는 명령
JPQL의 DISTINCT 2가지 기능 제공
sql에서 distinct는 페치조인의 중복된 결과를 거의 제거하지 못한다. 대부분 애플리케이션에서 엔티티 중복을 제거해준다.
일반 조인 실행시 연관된 엔티티를 함께 조회하지 않음
select t from team t join member m
(JPQL)의 결과
team_id | team_name |
---|---|
3 | team1 |
3 | team1 |
4 | team2 |
member의 정보는 조회되지 않았고, member 엔티티때문에 team의 정보만 뻥튀기되었다. (TEAM 엔티티기준)
만약 JPQL에 다른 엔티티의 필드를 직접 입력해서 쿼리를 보내면 원하는대로 가져오지만, 직접 attribute를 지정해주기 때문에 나중에 못쓸확률 높다
하지만 일반 join은 fetch join보다 조금 더 성능 최적화가 이루어진다는 장점이 있다.
페치 조인 대상에는 별칭을 줄 수 없다.
둘 이상의 컬렉션은 페치 조인 할 수 없다.
컬렉션을 페치 조인하면 페이징 API(setFirstResult, setMaxResults)를 사용할 수 없다.
여러 테이블을 조인해서 엔티티가 가진 모양이 아닌 전혀 다른 결과를 내야 하면, 페치 조인 보다는 일반 조인을 사용하고 필요 한 데이터들만 조회해서 DTO로 반환하는 것이 효과적