오봉이와 함께하는 개발 블로그
JPA 2 - 주문 조회V3 : 엔티티를 DTO로 변환(페치 조인 최적화) 본문
728x90
주문 조회 V3: 엔티티를 DTO로 변환 - 페치 조인 최적화
OrderApiController에 추가
@GetMapping("/api/v3/orders")
public List<OrderDto> orderV3() {
List<Order> orders = orderRepository.findAllWithItem();
List<OrderDto> result = orders.stream()
.map(o -> new OrderDto(o))
.collect(toList());
return result;
}
OrderRepository에 추가
public List<Order> findAllWithItem() {
return 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();
}
Order
와 OrderItems
를 join
하는데, Order
는 데이터가 2개, OrderItems
는 데이터가 4개 있다.
이것들을 join
하면 OrderItems
의 데이터 수 만큼 Order
의 데이터가 늘어나서 출력된다.
(OrderItems
에 같은 Order_Id
로 상품 두 개를 같이 주문했기 때문에 Order
하나에 OrderItems
는 두 개가 된다.)
이러면 문제는 JPA에서 데이터를 가져올 때도 데이터가 뻥튀기 된다.
그래서 distinct
를 사용하는 것이다!
DB의 distinct
는 row의 값이 모두 같아야 중복을 제거해준다.
하지만 JPA는 PK값이 같으면 같다고 판단해서 중복을 제거해준다.
- 페치 조인으로 SQL은 한번만 실행된다.
- distinct 를 사용한 이유는 일대다 조인이 있으므로 데이터베이스 row가 증가한다.
- 그 결과 같은 order 엔티티의 조회 수도 증가하게 된다.
- JPA의 distinct는 SQL에 distinct를 추가하고, 더해서 같은 엔티티가 조회되면, 애플리케이션에서 중복을 걸러준다.
- 예에서 order가 컬렉션 페치 조인 때문에 중복 조회 되는 것을 막아준다.
- 단점
- 일대다 컬렉션 페치 조인 하는 순간 페이징이 불가능하다.
컬렉션 페치 조인을 사용하면 페이징이 불가능하다. setFirstResult(n), setMaxResults(m)을 해도 쿼리는 하지 않았을 때의 쿼리와 동일하다. 하이버네이트는 경고 로그를 남기면서 모든 데이터를 DB에서 읽어오고, 메모리에서 페이징 해버린다. 페이징 되지 않은 엄청난 데이터가 동시 다발적으로 들어오게 된다면 매우 위험한 상황이 발생할 수 있다.
컬렉션 페치 조인(일대다에 대한 페치 조인)은 1개만 사용할 수 있다. 컬렉션 둘 이상에 페치 조인을 하면 일대다대다의 페치 조인을 해서 데이터가 뻥튀기 되어 JPA에서 데이터를 못 맞춰 부정합하게 조회될 수 있다.
인프런 김영한 지식공유자님 강의 - 실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
728x90
'BE > JPA' 카테고리의 다른 글
JPA 2 - 주문 조회V4 : JPA에서 DTO 직접 조회 (0) | 2022.09.06 |
---|---|
JPA 2 - 주문 조회V3.1 : 엔티티를 DTO로 변환(페이징과 한계 돌파) (0) | 2022.09.06 |
JPA 2 - 주문 조회V2 : 엔티티를 DTO로 변환 (0) | 2022.09.05 |
JPA 2 - 주문 조회 V1 : 엔티티 직접 노출 (0) | 2022.09.05 |
JPA 2 - 간단한 주문 조회 V4 : JPA에서 DTO로 바로 조회 (0) | 2022.09.05 |
Comments