-
[JPA] 페치조인 ( Fetch Join )Backend/JPA(Java Persistence API) 2022. 4. 2. 04:43728x90
이전 포스팅에서 즉시 로딩의 사용은 권장하지 않는다고 했었다.
https://yanglet.tistory.com/10
[JPA] 지연로딩과 즉시로딩
오늘은 지연로딩과 즉시로딩에 대해 정리해보겠다 즉시로딩이란? 즉시로딩은 엔티티를 조회할 때, 연관된 엔티티까지 한번에 조회하는 것을 말한다. 연관관계에 fetch = FetchType.EAGAR 로 설정을 해
yanglet.tistory.com
하지만 연관된 엔티티까지 한 번에 조회해 오고 싶을 수 있다.
그때 사용할 수 있는 것 중 하나가 JPQL의 페치조인이다. ( JPQL은 JPA에서 제공하는 객체 지향 쿼리 언어이다. )
페치조인이란?
페치조인은 연관된 엔티티나 컬렉션을 SQL 한 번에 조회하는 기능이다. ( 즉시 로딩의 기능 )
객체 그래프를 SQL 한번에 조회하는 개념.
SQL에서의 Inner Join, Outer Join 과 같은 조인 종류가 아니고 JPQL에서 성능 최적화를 위해 제공하는 기능이다.
join fetch 라는 명령어로 사용할 수 있다. ( 기본적으로 Inner Join 으로 SQL이 나가고, Outer Join 도 사용이 가능하다. )
JPQL 로 작성해보고 어떤 SQL로 나가는지 알아보자.
[ JQPL ]
select m from Member m join fetch m.team
이렇게 JPQL를 작성하면 Member 엔티티를 조회하는데,
Member 와 연관되어 있는 Team 까지 함게 조회하는 것이다. ( SQL 한번으로 )
[ SQL ]
SELECT M.*, T.* FROM MEMBER M INNER JOIN TEAM T ON M.TEAM_ID = T.ID
이렇게 SQL를 보면 Member 와 Team을 같이 조회해오는 쿼리가 나가게 된다.
페치 조인과 DISTINCT 키워드
그런데 컬렉션과 페치 조인을 할 경우에는 조인의 특성상 결과가 뻥튀기될 수 있다. ( 일대다 관계에서의 페치조인 )
SQL에서 DISTINCT 키워드는 모든 값이 같아야 같은 것으로 인식하고 중복을 제거해준다.
하지만 JPQL에서는 PK가 같은 엔티티의 중복을 제거하는 기능도 추가되어있다.
[ JPQL ]
select distinct t from Team t join fetch t.memebers where t.name = '팀A'
이 JPQL을 사용해서 결과를 가져오면 다음의 과정으로 결과를 반환한다.
1. SQL에 DISTINCT를 추가해서 쿼리를 날린다. 하지만 데이터가 전부 같지 않으므로 SQL 결과에서
중복제거에 실패한다.
2. DISTINCT가 추가로 애플리케이션에서 같은 식별자를 가진 Team 엔티티를 제거하고 하나만을 반환한다.
페치 조인의 특징과 한계
1. 페치 조인 대상에는 별칭을 줄 수 없다.
JPA 구현체인 하이버네이트에서는 가능하지만 가급적 사용X
select t from Team t join fetch t.memebers tms where tms.age > 10
하이버네이트를 이용해서 이런 식으로 사용할 수도 있지만 JPA의 설계 의도와 객체 그래프의 사상에 맞지 않음.
join fetch를 연달아서 사용해서 끌어와야 할 때 쓸 수도 있음.
2. 둘 이상의 컬렉션은 페치 조인 할 수 없다.
3. 컬렉션을 페치 조인하면 페이징 API ( setFirstResult, setMaxResults ) 를 사용할 수 없다.
select t from Team t join fetch t.memebers where t.name = '팀A'
이 경우로 보면 distinct 키워드가 없으므로 아래와 같은 결과를 반환하게 되는데
이때 한 개만 가져오고 싶다고 할 때 팀A의 속해있는 멤버가 회원1 하나만 있는 것으로 될 수가 있음.
하지만 하이버네이트를 사용하면 경고 로그를 남기고 메모리에서 페이징 해주기는 함. ( 매우 위험함 )
하이버네이트의 hibernate.default_batch_fetch_size 옵션 또는 @BatchSize 어노테이션을 이용해서
in 쿼리로 지정한 사이즈만큼 미리 당겨오는 것이 가능 !!
4. 연관된 엔티티들을 SQL 한 번으로 조회 - 성능 최적화
5. 지연 로딩을 기본적으로 사용하고 즉시 로딩이 필요할 때 사용할 수 있음
-> 글로벌 로딩 전략보다 우선함
참고 : 김영한 님의 인프런 강의 자바 ORM 표준 JPA 프로그래밍 - 기본 편
728x90'Backend > JPA(Java Persistence API)' 카테고리의 다른 글
[JPA] 엔티티에 Enum 컬렉션 담기 (0) 2022.05.23 [JPA] 지연로딩과 즉시로딩 (0) 2022.03.26 [최적화] readOnly조회 @QueryHint vs @Transactional (0) 2022.03.08