티스토리 뷰

컬렉션을 패치 조인하면 페이징이 불가능하다

- 컬렉션을 페치 조인하면 일대다 조인이 발생하므로 데이터가 예측할 수 없이 증가한다.

- 일대다에서 일(1)을 기준으로 페이징하는 것이 목적인데 다(N)을 기준으로 row가 생성된다.

- Order를 기준으로 페이징 하고 싶은데, 다(N)인 OrderItem을 조인하면 OrderItem이 기준이 되어버린다.

- 이 경우 하이버네이트는 경고 로그를 남기고 모든 DB 데이터를 읽어서 메모리에서 페이징을 시도한다. 최악의 경우 장애로 이어질 수 있다.

 

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

 

    public List<Order> findAllWithMemberDelivery(int offset, int limit){
        return em.createQuery("select o from Order o join fetch o.member m join fetch o.delivery d", Order.class)
                .setFirstResult(offset).setMaxResults(limit).getResultList();
    }

 

- 레퍼지토리에 jpql 쿼리를 하나 만들었다. 이번에는 toOne 관계 애들만 페치조인한다. toMany가 없기 때문에 정상적으로 페이징이 되어 값이 나온다(row도 정상).

 

application.yml

spring: #띄어쓰기 없음
  datasource: #띄어쓰기 2칸
    url: jdbc:h2:tcp://localhost/~/jpashop #4칸
    username: sa
    password:
    driver-class-name: org.h2.Driver

  jpa: #띄어쓰기 2칸
    hibernate: #띄어쓰기 4칸
      ddl-auto: create #띄어쓰기 6칸
    properties: #띄어쓰기 4칸
      hibernate: #띄어쓰기 6칸
        #show_sql: true #띄어쓰기 8칸
        format_sql: true #띄어쓰기 8칸
        default_batch_fetch_size: 100

logging.level: #띄어쓰기 없음
  org.hibernate.SQL: debug #띄어쓰기 2칸
  org.hibernate.type: trace #띄어쓰기 2칸

- default_batch_fetch_size를 추가해준다. 

 

  @GetMapping("/api/v3.1/orders")
    public List<OrderDto> ordersV3_page(@RequestParam(value="offset", defaultValue = "0") int offset,
                                        @RequestParam(value="limit", defaultValue = "100") int limit){
        List<Order> orders = orderRepository.findAllWithMemberDelivery(offset,limit); //toOne
        List<OrderDto> result = orders.stream().map(o -> new OrderDto(o)).collect(Collectors.toList());

        return result;
    }

    @Data
    static class OrderDto{

        private Long orderId;
        private String name;
        private LocalDateTime orderDate;
        private OrderStatus orderStatus;
        private Address address;
        private List<OrderItemDto> orderItems;

        public OrderDto(Order order){
            orderId = order.getId();
            name = order.getMember().getName();
            orderDate = order.getOrderDate();
            orderStatus = order.getStatus();
            address = order.getDelivery().getAddress();
            orderItems = order.getOrderItems().stream().map(orderItem -> new OrderItemDto(orderItem)).collect(Collectors.toList());
        }

    }

    @Getter
    static class OrderItemDto{
        private String itemName;
        private int orderPrice;
        private int count;

        public OrderItemDto(OrderItem orderItem){
            itemName = orderItem.getItem().getName();
            orderPrice = orderItem.getOrderPrice();
            count = orderItem.getCount();
        }
    }

 

- v3_page를 작동시키는데 처음 조회시에는 위의 레퍼지토리를 참고해보면 orderItem 과 item을 불러오지 않는다.

- DTO로 변환할 때에 값을 꺼내게 되어 LAZY 조회가 시작된다.

- 해당 로그를 확인해보자

select i1_0.item_id,i1_0.dtype,i1_0.name,i1_0.price,i1_0.stock_quantity,i1_0.artist,i1_0.etc,i1_0.author,i1_0.isbn,i1_0.actor,i1_0.director 
from item i1_0 where i1_0.item_id in (1,2,3,4);

 

- 이런 식으로 default_batch_fetch_size로 인해 in 쿼리가 발생하며 단 한번의 쿼리 조회로 값을 가져오게 된다. (orderitem도 쿼리 한개 날아간다.) (100으로 해두었으니 in은 100개가 최대로 나가며 부족할 경우 다시 100개를 처리한다)

- 페이징 처리가 가능해졌고, 트래픽처리도 되었다.

- 하이버네이트 6의 경우 100개를 불러오면 나머지는 NULL로 나가게 된다.

 

엔티티 내부에서 따로 적용도 가능하다.

toMany

    @BatchSize(size = 100)
    @OneToMany(mappedBy = "order", cascade = CascadeType.ALL) //cascade는 여러개를 한 번에 해줌.. 무슨말인지 잘모르겠다
    private List<OrderItem> orderItems = new ArrayList<>();

 

toOne

@BatchSize(size = 100)
@Entity
@Getter
@Setter
public class Member {

    @Id @GeneratedValue

 

김영한 선생님은 yml에서 잘 활용해서 사용하는 걸 추천하시는 듯 하다.

 

toMany가 들어갈 경우 페이징 및 성능 최적화 방법

  1. toOne으로만 불러온다
  2. default_batch_fetch_size를 적용
  3. toMany에 대한 초기화

순으로 적용하면 성능이 최적화 된다.

 

- 맥시멈은 default_batch_fetch_size 1000개 이다.

- 권장은 100~1000개이다.

- 하지만 100이든 1000이든 전체 데이터를 로딩해야 하므로 메모리 사용량이 같다.

- 1000으로 설정하는 것이 성능상 가장좋지만,결국 DB든 애플리케이션이든 순간 부하를 어디까지 견딜 수 있는지로 결정하면 된다.

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/10   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
글 보관함