본문 바로가기

Spring Data

JPQL 중급 문법 - 페치 조인1

페치 조인(fetch join)

  • SQL 조인 종류 X
  • JPQL에서 성능 최적화를 위해 제공하는 기능
  • 연관된 엔티티나 컬렉션을 SQL 한 번에 함께 조회하는 기능
  • join fetch 명령어 사용
// 페치 조인
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

 

String query = "select m from Member m";

List<Member> result = em.createQuery(query, Member.class)
	.getResultList();
    
for(Member member: result) {
	System.out.println("member.team.name: " + member.getTeam().getName() );
}
  • 회원1 => member.getTeam().getName() 호출 시, 지연 로딩으로 인해 쿼리 발생. 팀 A 조회, 1차 캐쉬 등록
  • 회원2 => member.getTeam().getName() 호출 시, 1차 캐쉬에 등록되어 있는 팀 A 조회
  • 회원3 => member.getTeam().getName() 호출 시, 지연 로딩으로 인해 쿼리 발생. 팀 B 조회, 1차 캐쉬 등록

만약 회원을 100명 조회, 최악의 경우 100번의 쿼리가 추가 실행됨.. 1 + N 문제 발생.

1 + N 이란  첫 번째 회원 조회 시 날린 쿼리 1회, 이후 조회해 온 N개의 회원의 팀을 조회하기 위해 N번 쿼리를 실행하기 때문에 1 + N이라 한다.

 

String query = "select m from Member m join fetch m.team";

List<Member> result = em.createQuery(query, Member.class)
	.getResultList();
    
// 페치 조인으로 회원과 팀을 함께 조회해서 지연로딩 x
for(Member member: result) {
	System.out.println("member.team.name: " + member.getTeam().getName() );
}

컬렉션 페치 조인

일대다 관계, 컬렉션 페치 조인

// 일대다 페치조인
select t 
from Team t join fetch t.members
where t.name = '팀A'


// 실제 실행되는 쿼리
select t.*, m* 
from team t join member m on i.id = m.team_id
where t.name = '팀A'

String jpql = "select 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.getMembers()) {
        //페치 조인으로 팀과 회원을 함께 조회해서 지연 로딩 발생 안함
        System.out.println(“-> username = " + member.getUsername()+ ", member = " + member); 
    }
}

// 결과값

/*
teamname = 팀A, team = Team@0x100
-> username = 회원1, member = Member@0x200
-> username = 회원2, member = Member@0x300
teamname = 팀A, team = Team@0x100
-> username = 회원1, member = Member@0x200
-> username = 회원2, member = Member@0x300
*/

 

페치 조인과 distinct

  • SQL의 distinct는 중복된 결과를 제거하는 명령
  • JPQL의 distinct 2가지 기능 제공
    • 1. SQL에 distinct를 추가
    • 2. 애플리케이션에서 엔티티 중복 제거
select distinct t
from Team t join fetch t.members
where t.name = '팀A'
  • SQL에 distinct를 추가하지만 데이터가 다르므로 SQL 결과에서 중복제거 실패

  • distinct가 추가로 애플리케이션에서 중복 제거 시도
  • 같은 식별자를 가진 Team 엔티티 제거

// distinct 추가 시 결과
/*
teamname = 팀A, team = Team@0x100
-> username = 회원1, member = Member@0x200
-> username = 회원2, member = Member@0x300
*/

페치 조인과 일반 조인의 차이

select t
from Team t join t.members m
where t.name = '팀A'
  • 일반 조인 실행 시 연관된 엔티티를 함께 조회하지 않음
  • JPQL은 결과를 반환할 때 연관관계를 고려하지 않는다.
  • 단지 select 절에 지정한 엔티티만 조회할 뿐
  • 여기서는 팀 엔티티만 조회하고, 회원 엔티티는 조회 x
  • 페치 조인을 사용할 때만 연관된 엔티티도 함께 조회(즉시 로딩)
  • 페치 조인은 객체 그래프를 SQL 한 번에 조회하는 개념.

 

 

'Spring Data' 카테고리의 다른 글

벌크 연산  (0) 2021.08.09
JPQL 중급 문법 - 페치조인2  (0) 2021.08.09
JPQL 중급 문법 - 경로표현식  (0) 2021.08.09
JPQL 기본 문법  (0) 2021.08.09
값 타입 #9  (0) 2021.07.26