본문 바로가기
JPA/JPA

[JPA] JPQL - 페치 조인(Fetch Join)

by 걸어가는 신사 2022. 1. 7.

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

댓글