-
컬렉션 조회 최적화 1 - 페치 조인을 안 했을 시JPA/JPA 활용 2023. 8. 10. 15:57
@OneToMany에서의 최적화를 하는 방법은 엔티티 조회 최적화보다 조금 더 까다롭다.
여기서도 이전 방식처럼 성능이 안 나오는 것부터 점진적으로 발전해나가면서 할 예정이다.
1. 엔티티를 그대로 노출
@GetMapping("/api/v1/orders") public List<Order> ordersV1() { List<Order> all = orderRepository.findAllByString(new OrderSearch()); for (Order order : all) { order.getMember().getName(); order.getDelivery().getAddress(); List<OrderItem> orderItems = order.getOrderItems(); orderItems.stream().forEach(o -> o.getItem().getName()); } return all; }
API를 만들 때 엔티티를 직접 노출하는 것은 좋지 않다고 여러번 얘기했다. 엔티티를 직접 노출하는 것은 피해야 한다.
2. DTO로 변환해서 반환하기
@GetMapping("/api/v2/orders") public List<OrderDto> ordersV2() { List<Order> orders = orderRepository.findAllByString(new OrderSearch()); List<OrderDto> collect = orders.stream() .map(o -> new OrderDto(o)) .collect(Collectors.toList()); return collect; }
OrderDto를 스트림으로 돌릴 때 Order 목록을 루프로 돌리고 Order에서의 orderItems 목록을 또 루프로 돌린다. 그런데 이 때에는 SQL이 너무 많이 나온다는 단점이 있다. Order를 조회하는 SQL에서 order가 2번 조회된다. 그 이후에 member, delivery의 쿼리가 나가고 orderItems에서 item이 2개가 있기 때문에 item을 찾는 쿼리가 2번 나간다. 이 과정이 첫 번째 order의 SQL 호출 과정이고 다음 주문에서도 쿼리가 이만큼 나간다.
쿼리가 너무 많이 나가기 때문에 성능상 문제가 되고 최적화를 더 신경써야만 한다.
OrderDto
@Getter static class OrderDto { private Long orderId; private String name; private LocalDateTime orderDate; private OrderStatus orderStatus; private Address address; private List<OrderItem> orderItems; // 여기에서 OrderItem이 들어간게 문제 public OrderDto(Order order) { orderId = order.getId(); name = order.getMember().getName(); orderDate = order.getOrderDate(); orderStatus = order.getStatus(); address = order.getDelivery().getAddress(); orderItems = order.getOrderItems(); } }
Dto를 만들 때에 주의점은 Dto에서도 엔티티를 사용하면 안된다는 것이다.
별도의 OrderItemDto를 만들어서 위에 있는 OrderItem도 OrderItemDto로 변환해줘야 한다.
@Getter static class OrderDto { .... private List<OrderItemDto> orderItems; // OrderItemDto로 보내기 public OrderDto(Order order) { .... orderItems = order.getOrderItems().stream() .map(orderItem -> new OrderItemDto(orderItem)) .collect(Collectors.toList()); // 여기도 Dto로 변환 필요 } } @Getter static class OrderItemDto { private String itemName; private int orderPrice; private int count; public OrderItemDto(OrderItem orderItem) { itemName = orderItem.getItem().getName(); orderPrice = orderItem.getItem().getPrice(); count = orderItem.getCount(); } }
Dto를 만들었어도 쿼리가 너무 많이 나가기 때문에 저번에 공부했던 fetch join을 이용해서 최적화를 진행해야 한다.
'JPA > JPA 활용' 카테고리의 다른 글
컬렉션 조회 최적화 3 - 페이징과 한계점 돌파 (0) 2023.08.10 컬렉션 조회 최적화 2 - fetch join으로 최적화 (0) 2023.08.10 간단한 주문조회 API - 지연 로딩과 조회 성능 최적화(2) (0) 2023.07.11 간단한 주문조회 API - 지연 로딩과 조회 성능 최적화 (0) 2023.07.11 회원 조회 API (0) 2023.07.11