250x250
Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
Tags
- 유니크제약조건
- 동적sql
- execute
- FetchType
- dfs
- fetch
- SQL프로그래밍
- 이진탐색
- PS
- 데코레이터
- 낙관적락
- 일대다
- 지연로딩
- 다대일
- 백트래킹
- 즉시로딩
- 스토어드 프로시저
- 다대다
- 스프링 폼
- 비관적락
- CHECK OPTION
- BOJ
- 연결리스트
- JPQL
- 힙
- eager
- exclusive lock
- shared lock
- querydsl
- 연관관계
Archives
- Today
- Total
흰 스타렉스에서 내가 내리지
페치 조인 :: join fetch 본문
728x90
# 페치 조인
- JPQL 에서 성능 최적화를 위해 제공하는 기능이다.
- 이것은 연관된 엔티티나 컬렉션을 한 번에 같이 조회하는 기능이다.
# 엔티티 페치 조인
- 회원 엔티티를 조회하면서 연관된 팀 엔티티도 함께 조회하는 JPQL
SELECT m
FROM Member m JOIN FETCH m.team
- 회원 (m) 과 팀 (m.team) 을 함께 조회한다.
* 실행된 SQL
SELECT
M.*, T.*
FROM Member M
INNER JOIN Team T ON M.team_id = T.id
- 엔티티 페치 조인 JPQL 에서 select m 으로 회원 엔티티만 선택했는데 실행된 SQL 을 보면 SELECT M.*, T.* 로 회원과 연관된 팀도 함께 조회된 것을 확인할 수 있다.
* 페치 조인을 사용하는 코드
String jpql = "SELECT m FROM Member m JOIN FETCH m.team";
List<Member> members = em.createQuery(jpql, Member.class)
.getResultList();
for (Member member : members) {
// 페치 조인으로 회원과 팀을 함꼐 조회해서 지연 로딩 발생 x
member.getUsername();
member.getTeam().getName();
}
- 팀도 함께 조회했으므로, 연관된 팀 엔티티는 프록시가 아닌 실제 엔티티다.
- 따라서 연관된 팀을 사용해도 지연 로딩이 일어나지 않는다.
# 컬렉션 페치 조인
- 엔티티 페치 조인이 One 쪽 하나를 함께 조회하는 것이었다면,
- 컬렉션 페치 조인은 Many, 즉 다 쪽(List) 를 함께 조회해 온다.
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'
- jpql 에서 , select t 로 팀만 선택했는데, SQL 을 보면 T.*, M.* 로 팀과 연관된 회원도 함께 조회되었다.
- 그 결과, 테이블에서 '팀A' 는 하나지만, MEMBER 테이블과 조인하면서 결과가 증가해서 같은 '팀A' 가 N 건 조회된다.
* 컬렉션 페치 조인 예제
이렇게 쓰면 안됨. 바로 아래 jpql 참고
String jpql = "select t from Team t join fetch t.members where t.name = '팀A'";
List<Team> teams = em.createQuery(jpql, Team.class).getResultList();
- 출력 결과를 보면 '팀A' 가 2건 조회된 것을 확인할 수 있다.
# 페치 조인과 DISTINCT
- JPQL 의 DISTINCT 명령어는 SQL에 DISTINCT 를 추가하는 것은 물론이고, 애플리케이션에서 한 번 더 중복을 제거한다.
- 바로 위 컬렉션 페치 조인은 팀A 가 중복으로 조회된다.
select distinct t
from Team t join fetch t.members
where t.name = '팀A'
- 먼저 DINSTINCT 가 SQL 에 추가된다
- 하지만, 각 데이터는 모두 다르므로 SQL 의 DISTINCT 효과는 없다.
- 다음으로 애플리케이션에서 distinct 명령어를 보고 중복된 데이터를 걸러낸다.
- select distinct t 의 의미는 팀 엔티티의 중복을 제거하라는 뜻이다.
# 페치 조인과 일반 조인의 차이
-- 내부 조인 JPQL
select t
from Team t join t.members m
where t.name = '팀A'
-- 실행된 SQL
SELECT
T.*
FROM TEAM T
INNER JOIN MEMBER M ON T.ID=M.TEAM_ID
WHERE T.NAME = '팀A'
- SQL의 SELECT 절을 보면 팀만 조회했고, 조인했던 회원은 전혀 조회되지 않는다.
- JPQL 은 단지 SELECT 절에 지정한 엔티티만 조회하기 때문에, 팀 엔티티만 조회하고 연관된 회원 컬렉션은 조회하지 않는다.
- 반면에 페치 조인을 사용하면 연관된 엔티티도 함께 조회한다.
# 페치 조인의 특징과 한계
- 페치 조인을 사용하면 SQL 한 번으로 연관된 엔티티들을 함께 조회할 수 있어서 SQL 호출 횟수를 줄여 성능을 최적화할 수 있다.
- 글로벌 로딩 전략은 될 수 있으면 지연 로딩을 사용하고 최적화가 필요하면 페치 조인을 적용하는 것이 효과적이다.
- 페치 조인 대상에는 별칭을 줄 수 없다.
- 데이터 무결성이 깨질 수 있다.
- 둘 이상의 컬렉션을 페치할 수 없다.
- 컬렉션을 페치 조인하면 페이징 API (setFirstResult, setMaxResult) 를 사용할 수 없다.
- 컬렉션이 아닌 단일 값 연관 필드들은 페치 조인을 사용해도 페이징 API 를 사용할 수 있다.
- 하이버네이트에서 컬렉션을 페치 조인하고 페이징 API 를 사용하면 경고 로그를 남기면서 메모리에서 페이징 처리를 한다.
- 데이터가 적으면 상관없겠지만, 데이터가 많으면 성능 이슈와 메모리 초과 예외가 발생할 수 있어서 위험하다.
* 여러 테이블을 조인해서 엔티티가 가진 모양이 아닌 전혀 다른 결과를 내야 한다면, 억지로 페치 조인을 사용하기보다는 여러 테이블에서 필요한 필드들만 조회해서 DTO 로 변환하는 것이 더 효과적일 수 있다.
'JPA' 카테고리의 다른 글
[JPQL] 조회해서 null 일 경우, 지정한 값을 반환하는 COALESCE (0) | 2024.04.14 |
---|---|
JPQL 서브쿼리, BETWEEN, IN, LIKE, NULL, 컬렉션 식 (0) | 2024.04.14 |
JPQL 페이징 API (0) | 2024.04.13 |
JPQL 에서 new 를 이용하여 DTO 클래스로 변환하여 받기 (0) | 2024.04.13 |
JPQL 파라미터 바인딩 (0) | 2024.04.13 |