조회하는 부분에서 속도가 너무 느려서 성능 최적화를 하기 위해 query를 자세히 살펴보았다.
역시 N+1문제가 발생하고 있었다.
N+1문제란?
JPA로 애플리케이션을 개발할 때 성능상 가장 주의해야 하는 문제다.
처음 조회한 데이터 수만큼 다시 SQL을 사용해서 조회하는 것이다.
예를 들면 회원이 5명이면 회원에 따른 주문도 5번 조회된다.
N+1이 발생하면 SQL이 상당히 많이 호출되므로 조회 성능에 치명적이다.
지연로딩으로 모두 설정해놔서 N+1문제에서 자유로울 것이라고 생각했는데 N+1 문제는 즉시 로딩과 지연 로딩일 때 모두 발생할 수 있다고 한다.
개선한 부분
1. 주변 식당 리스트 조회
- join fetch 적용 전

- join fetch 적용 후



식당조회시 리뷰까지 한 번에 받아오는 것을 볼 수 있다.
2. 마이페이지-내가 찜한 식당리스트
- 수정 전
-
List<RestaurantLikes> findAllByUser(User user, Pageable pageable);

- 1차 수정 후
@Query("select r from RestaurantLikes r join fetch r.restaurant where r.user = :user")
List<RestaurantLikes> findAllByUser(@Param(value = "user")User user, Pageable pageable);

식당에 연관된 리뷰에서는 여전히 N+1 문제가 발생했다.
fetch join을 또 사용해봤지만 오류가 났다. fetch join을 쓰는 데도 조건이 있었다.
* JPA에서 Fetch Join의 사용 조건
- ToOne은 몇개든 사용 가능
- ToMany는 1개만 가능
⇒ fetch join 두 개 사용할 수 없다.
- 2차 수정 후
Restaurant Entity에 추가
@org.hibernate.annotations.BatchSize(size = 100)
@OneToMany(mappedBy = "restaurant", cascade = CascadeType.ALL)
List<Review> reviews = new ArrayList<>();
해당 옵션은 지정된 수만큼 in절에 부모key를 사용하게 해준다.
즉, 1000개를 옵션값으로 지정하면 1000개 단위로 in절에 부모 Key가 넘어가서 자식 엔티티들이 조회되는 것이다.(글로벌로도 설정 가능하다.)


3. 모임 상세페이지 조회
- 수정 전

- 수정 후

findById로 meeting을 조회하던 부분을 위와 같이 query를 추가해줬다.

🤣성능개선 방법 정리
1. Fetch Join을 이용해 최대한의 성능 튜닝을 진행하고
2. Fetch Join으로 해결이 안되는 조회 쿼리에 대해서는 default_batch_fetch_size 옵션으로 최소한의 성능을 보장해준다.
global로 적용시 application.yml 파일에 추가해주면 된다.
N+1 문제가 발생하는 곳이 많아서 global로 적용되도록 수정했다.

Refactoring하면서 N+1문제가 발생하는 곳을 찾아서 모두 개선하여 성능최적화를 할 예정이다.
'개발 > Project' 카테고리의 다른 글
Spring Security에서 CORS 설정하기 (0) | 2023.01.19 |
---|---|
도메인 객체지향적으로 Refactoring 하기 (0) | 2022.02.13 |
JPA N+1 문제 해결 후 성능 비교해보기(2) (0) | 2022.02.07 |
[springBoot] test용 h2 DB 설정하기 (0) | 2022.01.24 |