1. 페치 조인(fetch join): 실무에서 정말정말 중요하다
sql의 조인 종류가 아니라 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
-컬렉션 페치 조인
일대다 관계에서 컬렉션 페치 조인을 사용한다
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 m.team_id=t.id where t.name='팀A'
-페치 조인과 DISTINCT
DISTINCT가 추가로 애플리케이션에서 중복 제거를 시도한다
같은 식별자를 가진 Team 엔티티를 제거한다
-페치 조인과 일반 조인의 차이
일반 조인 실행했을 때는 연관된 엔티티를 함께 조회하지 않는다
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 m.team_id =t.id where t.name='팀A'
JPQL은 결과를 반환할 때 연관관계를 고려하지 않는다. 단지 select 절에 지정한 엔티티만 조회한다.
여기서는 팀 엔티티만 조회하고, 회원 엔티티는 조회하지 않는다
페치 조인을 사용할 때만 연관된 엔티티도 함께 조회한다(즉시 로딩)
페치 조인은 객체 그래프를 SQL 한번에 조회하는 개념이다
일대다 조인은 데이터가 뻥튀기 될 수 있다
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'
-페치 조인의 특징과 한계
1) 특징
연관된 엔티티들을 SQL 한번으로 조회한다. 성능이 최적화한다
엔티티에 직접 적용하는 글로벌 로딩 전략보다 우선한다
@OneToMany(fetch=FetchType.LAZY) //글로벌 로딩 전략
실무에서 글로벌 로딩 전략은 모두 지연로딩
최적화가 필요한 곳은 페치 조인을 적용한다
2)한계
페치 조인 대상에는 별칭을 줄 수 없다. 하이버네이트에서는 가능 하지만, 가급적 사용하지 않는다
페치 조인에서 컬렉션은 하나만 지정할 수 있다
둘 이상의 컬렉션은 페치 조인을 할 수 없다
컬렉션을 페치 조인하면 페이징 API(setFirstResult,setMaxResults)를 사용할 수 없다.
일대일, 다대일 같은 단일 값 연관 필드들은 페치 조인해도 페이징이 가능하지만, 하이버네이트는 경고 로그를 남기고 메모리에서 페이징한다(매우 위험하다)
페치조인에 페이징을 쓰지 못하는데 사용해야하는 경우에는
@BatchSize를 추가하거나 설정에서 batchsize 의존성을 추가한다
=====> 정리
모든 것을 페치 조인으로 해결할 수는 없다
페치 조인은 객체 그래프를 유지할 때 사용하면 효과적이다
여러 테이블을 조인해서 엔티티가 가진 모양이 아닌 전혀 다른 결과를 내야하면, 페치 조인 보다는 일반 조인을 사용하고 필요한 데이터들만 조회해서 dto로 반환하는 것이 효과적이다
3가지 방법
- 엔티티를 페치조인으로 조회한다 그걸 쓴다
- 페치조인을 써서 애플리케이션에서 dto로 바꿔서 뷰에 반환
- 처음부터 jpql을 짤 때 new operation으로 dto로 반환해서 불러온다
2. 다형성 쿼리(TYPE,TREAT)
-TYPE
: type(i) in (a,b), 조회 대상을 특정 자식으로 한정한다
예시) Item 중에 Book, Movie를 조회해라
JPQL: select i from Item i where type(i) IN (Book,Movie)
SQL: select i from i where i.DTYPE in('B','M')
-TREAT
: Treat(parent as child), 자바의 타입 캐스팅과 유사하다
상속 구조에서 부모 타입을 특정 자식 타입으로 다룰 때 사용한다
from,where,select(하이버네이트 지원)에서 사용한다
예시) 부모인 Item과 자식 Book이 있다
JPQL: select i from Item i where treat(i as Book).author='Kim'
SQL: select i.* from Item i where i.DTYPE='B' and i.author='Kim'
3. JPQL- 엔티티 직접 사용
-기본키 값:
JPQL에서 엔티티를 직접 사용하면 SQL에서 해당 엔티티의 기본키 값을 사용한다 (엔티티 사용-> 엔티티 PK값 사용)
JPQL:
select count(m.id) from Member m //엔티티의 아이디를 사용
select count(m) from Member m // 엔티티를 직접 사용
SQL: select count(m.id) as cnt from Member m
4. Named 쿼리
미리 정의해서 이름을 부여해두고 사용하는 JPQL이다
정절 쿼리이며 어노테이션/XML에 정의한다
애플리케이션 로딩 시점에 초기화 후 재사용한다
애플리케이션 로딩 시점에 쿼리를 검증한다
-Named 쿼리 환경에 따른 설정
xml이 항상 우선권을 가진다
애플리케이션 운영 환경에 따라 다른 xml을 배포할 수 있다
5. 벌크 연산
만약 재고가 10개 미만인 모든 상품의 가격을 10% 상승하려면?
JPA 변경 감지 기능으로 실행하려면 너무 많은 SQL을 실행해야한다
( 재고가 10개 미만인 상품을 리스트로 조회한다 -> 상품 엔티티의 가격을 10% 증가 시킨다 -> 트랜잭션 커밋 시점에 변경감지가 동작한다)
이때 변경된 데이터가 100건이라면 100번의 UPDATE SQL을 실행해야한다
-주의
벌크 연산은 영속성 컨텍스트를 무시하고 데이터베이스에서 직접 쿼리한다
벌크 연산을 먼저 실행-> 영속성 컨텍스트를 초기화한다
'JPA' 카테고리의 다른 글
[JPA] OSIV에 대해서 (0) | 2022.03.19 |
---|---|
[JPA] 2/24 공부내용 정리(경로 표현식, 경로탐색, 묵시적 조인) (0) | 2022.02.26 |
[JPA] 2/24 공부내용 기록(조인,on 절, 서브쿼리) (0) | 2022.02.26 |
[JPA] 2/22 공부 내용 기록(값타입,Embedded Type) (0) | 2022.02.25 |
[JPA] 2/22 공부내용 기록(지연 로딩, cascade, 고아객체) (0) | 2022.02.25 |