1. 페치 조인 (Fetch Join)
- SQL 조인 종류가 아니다.
- JPQL에서 성능 최적화를 위해 제공하는 기능이다.
- 연관된 엔티티나 컬렉션을 SQL 한 번에 함께 조회하는 기능을 한다. (지연 로딩을 무시한다.)
- join fetch 명령어 사용
- 페치 조인은 별칭을 사용할 수 없다.
- 하이버네이트는 페치 조인에도 별칭을 허용한다.
페치 조인 ::= [LEFT [OUTER] | INNER ] JOIN FETCH 조인 경로
2. 페치 조인과 일반 조인의 차이
(1) 일반 조인
//일반 조인
String query = "select m from Member m join m.team t";
- JPQL은 결과를 반환할 때 연관관계를 고려하지 않는다.
- 회원과 팀을 조인했으므로 팀이 함께 조회할 것으로 기대해선 안된다.
- 회원 엔티티는 조회하고 팀 엔티티는 조회하지 않는다.
- 각 회원 객체에 대한 팀을 Select 하는 쿼리가 각각 날아간다. (N+1) 문제 발생
(2) 페치 조인
//페치 조인
String query = "SELECT m FROM Member m JOIN FETCH m.team";
- 페치 조인을 사용하면 연관된 엔티티도 함께 조회된다.
- 이후 m.team.getName() 메소드 호출하여도 쿼리가 나가지 않는다.
3. 엔티티 페치 조인
- 페치 조인 사용 코드
String query = "SELECT m FROM Member m JOIN FETCH m.team";
List<Member> members = em.createQuery(query, Member.class).getResultList();
for (Member member : members) {
System.out.println(member);
System.out.println(member.getTeam().getName());
}
- select m으로 회원 엔티티만 선택했는데 실행된 SQL을 보면 회원과 연관된 팀도 함께 조회된 것을 확인할 수 있다.
- 회원과 팀을 지연 로딩으로 설정하였더라도 페치 조인 사용 시에 지연 로딩이 일어나지 않는다.
- 회원, 팀 엔티티 모두 프록시가 아닌 실제 엔티티이다.
4. 컬렉션 페치 조인
- 일대다 관계, 컬렉션 페치 조인
- 페이징 기능을 사용할 수 없다.
String query = "select t from Team t join fetch t.members where t.name='teamA'";
List<Team> teams = em.createQuery(query, Team.class).getResultList();
for (Team team : teams) {
System.out.println(team.getName());
for (Member member : team.getMembers()) {
System.out.println(member);
}
}
- 팀과 연관된 회원도 함께 조회한 것을 확인할 수 있다.
- TEAM 테이블에서 "teamA"는 하나지만 MEMBER 테이블과 조인하면서 결과가 증가해서 조인 결과 테이블이 2건이 되었다.
- 일대다 조인은 결과가 증가할 수 있다.
5. 페치 조인과 DISTINCT
- SQL의 DISTINCT는 중복된 결과를 제거하는 명령이다
- JPQL의 DISTINCT 2가지 기능 제공한다
- SQL에 DISTINCT를 추가한다.
- 애플리케이션에서 엔티티 중복을 제거한다.
String query = "select distinct t from Team t join fetch t.members where t.name='teamA'";
- SQL에 DISTINCT를 추가하지만 데이터가 다르므로 SQL 결과에서 중복제거를 실패한다.
- 애플리케이션에서 DISTINCT 명령어를 보고 중복된 데이터를 걸러낸다.
- 같은 식별자를 가진 Team 엔티티를 제거한다.
6. 페치 조인의 특징과 한계
(1) 특징
- SQL 한 번으로 연관된 엔티티들을 함께 조회할 수 있어서 SQL 호출 횟수를 줄여 성능을 최적화할 수 있다.
- 엔티티에 직접 적용하는 글로벌 로딩 전략보다 우선한다.
- @OneToMany(fetch = FetchType.LAZY) => 글로벌 로딩 전략
- 실무에서는 글로벌 로딩 전략은 모두 지연 로딩이다.
- 최적화가 필요한 곳은 페치 조인을 적용하면 효과적이다.
(2) 한계
- 페치 조인 대상에는 별칭을 줄 수 없다.
- 따라서 SELECT, WHERE 절, 서브 쿼리에 페치 조인 대상을 사용할 수 없다.
- 하이버네이트는 별칭 사용이 가능하지만, 사용하지 말자.
- 컬렉션 페치 조인에서 페이징 기능을 사용할 수 없다.
- 둘 이상의 컬렉션을 페치 할 수 없다.
- 컬렉션을 페치 조인하면 페이징 API (setFirstResult, setMaxResults)를 사용할 수 없다.
- 일대일, 다대일 페치 조인을 사용해도 페이징 API를 사용할 수 있다.
반응형
'JPA > JPA' 카테고리의 다른 글
[JPA] JPQL - 조건식 (0) | 2022.01.08 |
---|---|
[JPA] JPQL - 경로 표현식(Path Expression)과 묵시적 조인 (0) | 2022.01.07 |
[JPA] JPQL - 조인(Join) (0) | 2022.01.07 |
[JPA] JPQL - 기본 문법 (0) | 2022.01.07 |
[JPA] 값 타입 (0) | 2022.01.04 |
댓글