JPQL 페치조인의 특징과 한계
-페치조인 대상에는 별칭을 줄 수 없다.
//join fetch t.team as t 이런거 하면 안됨 , 하이버네이트는 가능하지만 가급적 사용하지말것
-둘 이상의 컬렉션을 페치조인 할 수 없다.
-컬렉션을 페치조인하면 페이징 API를 사용할 수 없다.
ㄴ일대일 , 다대일 같은 단일값 연관 필드들은 페치조인해도 페이징 가능
ㄴ하이버네이트는 경고 로그를 남기고 메모리에서 페이징(매우 위험)
fetch조인은 엔티티와 연관된것 모든것을 끌고 오겟다는것
이때 추가적인 엔티티들에 영향을 주지 않는게 원칙이다.
그 이유는 전부가져오는것은 일부만 조작할 경우가 있을수 있기 떄문
객체 그래프는 기본적으로 데이터를 전부 조회해야한다.
필요 없는걸 걸러가면서 조회할 수는 없다.
이런 경우가 없는건 아니지만 그 경우에는 fetch가 아니라
처음부터 필요한것만 조회해야한다.
JPA는 기본적으로 객체그래프 모두 가져오는것을 원칙으로 한다.
둘 이상의 컬렉션의 경우 데이터가 생각치못한 수준으로 늘어나서 사용하면 안된다.
컬렉션의 경우 하나면 fetch join 할것
데이터 뻐우티기에 경우 페이징이 되지않는다.
안되는 이유는
팀 A가 회원1 , 회원2를 가진경우 (데이터 뻥튀기로 늘어남)
1개 값만 가져와 페이징하면
팀A - 회원1 까지만 가져와 마치 데이터가 1개뿐인것 처럼 보여지기 때문이다.
그래서 JPA가 데이터를 일단 전부 가져와버리기 떄문에 문제 발생
일대다 를 다대일로 만들거나 fetchJoin을 아예 빼거나
그런데 fetch를 빼면 지연로딩을 여러번 쓰기때문이 효율이 나질 않는다.
fetch를 뺀경우의 해결책으로
@BatchSize(size = 100)
@OneToMany(mappedBy = "team")
private List<Member> members = new ArrayList<>();
해당 필드에 BatchSize 옵션을 주고
select t from Team t; 를 하게되면
객체그래프로 찾을 경우 트리구조로 계속 찾게되는데
List<Team> result = em.createQuery(query,Team.class)
.setFirstResult(0)
.setMaxResult(2)
.getResultList();
결과값 2개를 얻고
그 결과값의 객체 그래프탐색을 할 경우
BatchSize에 설정해둔 만큼 IN절에 엔티티의 PK값을 넣어 쿼리를 최소화 한다.
이또한 N+1이긴 하다.
*해결책*
엔티티의 N+1문제는 fatch Join으로 해결
컬렉션의 N+1문제는 BatchSize로 해결
BatchSize는 글로벌로 설정할 수 있는데
JPA설정(Persistence)에서
<property name = "hibernate.default_batch_fetch_size" value="100"/>
으로 글로벌로 설정이 가능하다.
연관된 엔티티들은 SQL 한번으로 조회 - 성능 최적화
엔티티에 직접 적용하는 글로벌 로딩전략보다 우수함
OneToMant(fetch = FetchType.LAZY) // 글로벌 로딩 전략
실무에서 글로벌 로딩전략은 모두 지연로딩으로 설정한다.
최적화가 필요한 곳은 페치조인 적용
N+1은 대게 fetchJoin 으로 해결가능
페치조인 정리
-모든 것을 페치조인으로 해결할 수는 없음
-페치조인은 객체 그래프를 유지할때 사용하면 효과적
-여러 테이블을 조인해서 엔티티가 가진 모양이 아닌 전혀 다른 결과를 내야한다면
페치조인보다 일반 조인을 사용하고 필요한 데이터들만 조회해서 DTO로 반환하는것이 효과적이다.
'JPA' 카테고리의 다른 글
| 2월 17일 JPA JPQL 엔티티 직접 사용 (0) | 2023.02.17 |
|---|---|
| 2월 17일 JPA JPQL 다형성 쿼리 (0) | 2023.02.17 |
| 2월 16일 JPA 일대다 관계, 컬렉션 페치 조인 (0) | 2023.02.16 |
| 2월 16일 JPA JPQL fetch Join (0) | 2023.02.16 |
| 2월 15일 JPA JPQL 경로 표현식 (0) | 2023.02.15 |