JPQL - fetch join 기본

InOut·2023년 7월 24일

JPA

목록 보기
4/4

이번에는 JPQL에서 굉장히 중요한 페치 조인에 대해서 알아보자.



JPQL - 페치 조인(fetch join) 기본

  • SQL 조인 종류 X
  • JPQL에서 성능 최적화를 위해 제공하는 기능
  • 연관된 엔티티나 컬렉션을 SQL 한 번에 함께 조회하는 기능
  • join fetch 명령어 사용
  • 페치조인 ::= [ LEFT [OUTER] | INNER ] JOIN FETCH 조인 경로

엔티티 페치조인

엔티티 페치 조인

  • 회원을 조회하면서 연관된 팀도 함께 조회 (SQL 한 번에)
  • SQL을 보면 회원 뿐만 아니라 팀(T.*)도 함께 SELECT

[JPQL]
select m from Member m join fetch m.team
[SQL]
SELECT M.*, T.* FROM MEMBER M
INNER JOIN TEAM T ON M.TEAM_ID = T.ID

회원과 그와 관련된 팀을 조회한다고 가정해보자.


- 현재 Member 와 Team은 연관관계가 매핑이 되어있고 Team의 입장에서는 ManyToOne이다. 또한 지연로딩으로 설정되어있다


  • 회원1과 회원2는 팀A소속, 회원3은 팀 B소속이다
  • 예제이기때문에 flush()를 통해 영속성컨텍스트를 db에 반영하고 clear()를 통해 영속성컨텍스트를 비워주자


  • 아래와 같은 코드로 회원과 회원이 속한 팀의 이름을 조회한다.


  • 실행결과


위의 경우 문제가 되는것이 무엇일까?
일단 코드를 살펴보자

1. 아래의 코드에서 select 쿼리가 나가고 조회결과(Member)를 영속성컨텍스트에 저장한다.
List<Member> result = em.createQuery(query, Member.class)
						.getResultList();

2. for()문안에 출력문에서 member.getUsername()은 회원정보가 1차캐시(영속성컨텍스트)에 
	존재하기 때문에 뽑아올 수 있지만 회원이 속한 팀의 정보(member.getTeam().getName())
    는 영속성컨텍스트에 없기 때문에 조회쿼리를 날리게 된다. (팀A에 대한 정보를 조회)
3. for()문 마지막에서의 회원3에 대한 팀B의 정보 또한 없기 때문에, 조회 쿼리를 또 날린다.

*** 여기서 team은 프록시 객체이다. ***
                       

위의 설명과 같이 회원 100명에 대한 정보를 가져오기 위해 최악의 경우 쿼리가 100번 나가게된다. ( N + 1 문제)

그렇다면 이런 문제를 어떻게 해결해야할까?
바로 페치조인(fetch join)이다.

  • 조회결과를 보면 페치조인으로 인해 쿼리가 한번만 나가게 되고 Team은 프록시 객체가 아니라는것을 알 수 있다.
  • 이렇게 사용하면 지연로딩 없이 깔끔하게 회원과 팀을 함께 조회 가능하다.

컬렉션 페치 조인

  • 일대다 관계

  • [JPQL]
    select t
    from Team t join fetch t.members
    where t.name = '팀A'

  • [SQL]
    SELECT T.*, M.*
    FROM TEAM T
    INNER JOIN MEMBER M ON T.ID = M.TEAM_ID
    WHERE T.NAME = '팀A'


이 글은 김영한님의 JPA 강의를 듣고 정리한 내용입니다.

profile
개발새발

0개의 댓글