컬렉션 조회 최적화

HUSII·2023년 7월 10일
0

JPA

목록 보기
4/7

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();

컬렉션 페치조인의 단점은 페이징이 불가능하다는 점이다.

페이징 함수를 사용할 수는 있지만, 메모리에서 페이징을 진행한다 -> 매우 위험하다

그리고 두개 이상의 컬렉션에 대한 페치조인은 불가능하다.


그러면 페이징 + 컬렉션 엔티티를 함께 조회하려면 어떻게 해야할까?

아래와 같은 방법으로 해결할 수 있다.

  • 먼저 ToOne(OneToOne, ManyToOne) 관계를 모두 페치조인 한다. ToOne 관계는 row수를 증가시키지 않으므로 페이징 쿼리에 영향을 주지 않는다.
  • 컬렉션은 지연 로딩으로 조회한다.
  • 지연 로딩 성능 최적화를 위해 hibernate.default_batch_fetch_size , @BatchSize 를 적용한다.

    hibernate.default_batch_fetch_size: 글로벌 설정
    @BatchSize: 개별 최적화
    이 옵션을 사용하면 컬렉션이나, 프록시 객체를 한꺼번에 설정한 size 만큼 IN 쿼리로 조회한다.


Dto로 조회

방법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방식은 재사용성이 낮다는 단점이 있다)

profile
공부하다가 생긴 궁금한 것들을 정리하는 공간

0개의 댓글