페치 조인(Fetch Join)
- JPQL에서 성능 최적화를 위해 제공하는 기능
- 연관된 엔티티나 컬렉션을 SQL 한 번에 함께 조회할 수 있다.
join fetch
엔티티 페치 조인
@OneToOne
, @ManyToOne
- 회원을 조회하면서 연관된 팀도 함께 조회
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
컬렉션 페치 조인
@OneToMany
- 팀을 조회하면서 속한 회원 컬렉션을 함께 조회
- 조인 테이블을 그대로 들고오기 때문에, 카테시안 곱으로 이름이 '팀A'인 컬렉션의 사이즈가 2가 되어버린다.
- 이를 방지하기 위해서 t를 가져올 때
distinct
로 가져온다.
String jpql = "select distinct t from Team t join fetch t.members where t.name = '팀A'"
List<Team> teams = em.createQuery(jpql, Team.class).getResultList();
for (Team team : teams) {
System.out.println("teamname = " + team.getName() + ", team = " + team);
for (Member member : team.getMemabers()) {
System.out.println(" -> username = " + member.getUsername() + ", member = " + member);
}
}
페치 조인과 DISTINCT
- SQL의
DISTINCT
는 중복된 결과를 제거하는 명령
- JPQL의
DISTINCT
는 2가지 기능 제공
- SQL에 DISTINCT를 추가 ← 하지만 조인 테이블은 완벽하게 모든 컬럼 값이 같지 않으므로 중복제거 실패한다.
- 애플리케이션(영속성 컨텍스트)에서 엔티티 중복 제거
페치 조인의 한계
- 페치조인 대상에는 별칭을 줄 수 없다.
- 둘 이상의 컬렉션은 페치 조인을 할 수 없다.
- 컬렉션을 페치조인하면 페이징 API를 사용할 수 없다.
- 페치 조인은 객체 그래프를 유지할 때 사용하면 효과적이지만, 모든 것으르 페치조인으로 해결할 수는 없다.
- 여러 테이블을 조인해서 엔티티가 가진 모양이 아닌 전혀 다른 결과를 내야 하면, 페치 조인 보다는 일반 조인을 사용하고 필요한 데이터들만 조회해서 DTO로 반환하는 것이 효과적이다. (프로젝션)
참고자료
- 자바 ORM 표준 JPA 프로그래밍, 김영한 저