ToMany 연관관계를 한번에 조회할때의 경우
이전 엔티티 조회와 달리 컬렉션을 조회하는 것은 매우 복잡하다.
Order, OrderItem, Item 총 3개의 엔티티가 있다.
OrderItem과 Item는 ManyToOne 관계
Order와 OrderItem는 OneToMany 관계
페치조인과 distinct를 사용하면 쿼리 1번만에 모두 조회 가능하다.
em.createQuery(
"select distinct o from Order o" +
" join fetch o.member m" +
" join fetch o.delivery d" +
" join fetch o.orderItems oi" +
" join fetch oi.item i", Order.class)
.getResultList();
컬렉션 페치조인의 단점은 페이징이 불가능하다는 점이다.
페이징 함수를 사용할 수는 있지만, 메모리에서 페이징을 진행한다 -> 매우 위험하다
그리고 두개 이상의 컬렉션에 대한 페치조인은 불가능하다.
그러면 페이징 + 컬렉션 엔티티를 함께 조회하려면 어떻게 해야할까?
아래와 같은 방법으로 해결할 수 있다.
hibernate.default_batch_fetch_size: 글로벌 설정
@BatchSize: 개별 최적화
이 옵션을 사용하면 컬렉션이나, 프록시 객체를 한꺼번에 설정한 size 만큼 IN 쿼리로 조회한다.
방법1
맨처음 ToOne 관계들의 페치조인 진행
-> ToMany 관계 하나씩 지연로딩 get
1+n개의 쿼리 나간다.
방법2
ToOne 관계끼리 조회한다.
order, member, delivery and orderItem, item
-> map을 이용해서 애플리케이션에서 정리해준다
1+1 쿼리만 나간다.
조회하려는 데이터의 개수가 적다면 1번이 더 빠를수있다.
하지만 대용량 데이터는 2번이 무조건 빠르다.
맨처음에는 fetch join을 시도해보고(쿼리1번)
만약 페이징함수가 필요하다면
hibernate.default_batch_fetch_size , @BatchSize 를 이용해서 ToOne 관계 fetch join 후 각각의 컬렉션을 지연로딩으로 가져오자(1+1 쿼리)
만약 엔티티 방식으로 해결이 안된다면 Dto로 시도해보자
(Dto방식은 재사용성이 낮다는 단점이 있다)