DevKim

[성능 최적화] 지연로딩과 조회 성능 : XToOne 본문

Spring Boot

[성능 최적화] 지연로딩과 조회 성능 : XToOne

on_doing 2021. 7. 13. 18:03
728x90

" 현재 주문과 회원은 N:1의 관계이고, 주문과 주소의 관계는 1:1관계이다. "

- 현재 각각 다른 회원이 2개의 주문을 넣어놨고, 주문에서 회원과 주소를 조회하려고하는 상황이다.

( = 주문 + 배송정보 +회원 조회)

 

- XToOne의 관계이므로 모두 지연로딩 관계로 설정해놓은 상태이다.

 

*참고*

지연로딩은 조회시 영속성 컨텍스트에 있으면 SQL 실행 X

영컨에 없으면 SQL 실행

 

- 지연로딩 때문에 발생하는 성능 문제를 단계적으로 해결해보자.


[ Case #1. ]

엔티티를 DTO로 변환해서 조회하기

: 어쩌면 제일 보편적으로 사용하고 있는 방법이다.

@GetMapping("/api/orders")
public void order01()
{
     List<Order> orders = orderRepository.findAll(); //주문 건수 2개
     List<SimpleOrderDto> result = orders.stream()
 				.map(OrderDto::new)
 				.collect(toList());
}

 

@Data
static class OrderDto {
 private Long orderId;
 private String name;
 private LocalDateTime orderDate;
 private OrderStatus orderStatus;
 private Address address;
 public SimpleOrderDto(Order order) {
 orderId = order.getId();
 name = order.getMember().getName(); // LAZY 초기화
 orderDate = order.getOrderDate();
 orderStatus = order.getStatus();
 address = order.getDelivery().getAddress(); //LAZY 초기화
 }
}

이렇게 되면 주문을 2번 조회했을 때, 쿼리는 몇 번이 나가게될까?

 

차근차근 생각을 해보자.

 

1. findall로 주문 조회 (쿼리+1) -> 주문이 2건이 있다.

2. 주문 #1 ->  member 조회 (쿼리 +1), delivery 조회(쿼리 +1)

3. 주문 #2 ->  member 조회 (쿼리 +1), delivery 조회(쿼리 +1)

 

=> 총 5개의 쿼리가 나가게 된다.

=> 100개를 조회하게 된다면 ..?

N+1의 문제가 심각해진다 ㅠㅠ

 

그렇다고 EAGER로 한다면??? 예측할 수 없는 쿼리가 왕창 나가면서 난리가 난다..


[ Case 2. ]

엔티티를 DTO로 변환 + 페치 조인으로 최적화

 

이번엔 페치 조인을 추가하여 order을 조회해보자

@GetMapping("/api/orders")
    public void order01()
    {
        List<Order> orders = findAllWithMemberDelivery.findAll(); //주문 건수 2개
        List<SimpleOrderDto> result = orders.stream()
                .map(OrderDto::new)
                .collect(toList());
    }

member와 delivery까지 한방쿼리로 같이 가져온다.

public List<Order> findAllWithMemberDelivery()
    {
        em.createQuery(
                "select o from Order o"+
                " join fetch o.member m"+
                " join fetch o.delivery d",Order.class)
                .getResultList();
    }

그 다음으론,

JPA에서 DTO로 바로 조회하는 경우이다.

 

이 경우도 장점과 단점이 있다고하는데,

개인적으로 DTO를 바로 조회하는건 repository의 재사용성이 너무 떨어지는 것 같아서 최대한 사용안하고싶다..ㅎ

 

 

쿼리 방식 선택 권장 순서

1. 우선 엔티티를 DTO로 변환하는 방법을 선택한다.

2. 필요하면 페치 조인으로 성능 최적화 (거의 대부분 해결)

3. 그래도 안되면 DTO로 직접 조회하는 방법을 사용한다.

4. 최후의 방법은 JPA가 제공하는 네이티브 SQL이나 스프링 JDBC Template를 사용해서 SQL을 직접 사용

 

 

728x90
Comments