REST API 성능 최적화, 엔티티 조회와 필터링

dropKick·2020년 9월 11일
0

정리

엔티티 조회 방식

public List<Order> findAllWithItem() {
        return em.createQuery(" select 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();
    }
  • JPQL을 통해 조회된 데이터는 엔티티 자체로 반환
  • 엔티티 자체를 반환받기 때문에 JPA 구현체에 의한 성능 최적화 기법들을 사용가능
  • 엔티티가 변경되어도 DTO를 변경하면 API 스펙에 영향을 끼치지 않음

DTO 조회 방식

private List<OrderQueryDto> findOrders() {
        return em.createQuery(
                "select new jpabook.jpashop.repository.order.query.OrderQueryDto(o.id, m.name, o.orderDate, o.status, d.address) from Order o"
                        + " join o.member m"
                        + " join o.delivery d", OrderQueryDto.class)
                .getResultList();
    }
  • JPQL 조회 시 데이터 자체가 DTO를 통해 반환
  • 직접 각 쿼리마다 별도의 DTO를 생성
  • JPA 구현체에 의한 성능 최적화 사용불가
  • 엔티티 변경 시 관련된 모든 걸 변경해야 함

결론

API 최적화의 경우 다음의 순서를 권장한다.

  1. 엔티티를 접근한 뒤 DTO로 변환하기
  2. fetch 조인을 통해 쿼리 최적화하기
  3. 1:N 컬렉션 최적화하기
    • 페이징이 필요한 경우
      hibernate batch size를 통해 페이징
      애플리케이션 메모리에 모든 쿼리 데이터를 적재하므로 적절한 페이징 필요
    • 페이징이 필요없는 경우
      fetch 조인을 사용
  4. 위 모든 방법을 사용했을 때 더욱 최적화가 필요한 경우 DTO JPQL 직접 생성
    DTO JQL 직접 생성 방식은 각 최적화 쿼리마다 별도의 코드 생성이 필요하므로 재사용성이 떨어진다.

따라서 개발자는 최적화와 코드의 재사용성 사이에서 트레이드 오프가 필요하다.

만약 1:N에서 조건 필터링이 필요한 경우

주문내역을 조회할 때 '책'이라는 상품이 주문된 내역을 조회하려고 할 때
order, orderItem, item에 fetch 조인을 사용할 수 있을까?

  • 불가능
    fetch 조인은 기본적으로 부분 필터링이 불가능하다
    따라서 join where('책') + 페이징을 통해 쿼리 데이터를 받아온 뒤
    애플리케이션에서 order로 변환해야 한다.

추가 링크

0개의 댓글