항해99 - 실전 프로젝트, N+1 문제 성능 개선

2024. 4. 25. 18:53· 항해99 개발일지
목차
  1. ✔️ N+1 문제 발생
  2. 💬 원인 분석
  3. ✔️ 해결 및 개선
  4. ✔️ 성능 비교 테스트 결과 - 개선 전 vs  개선 후
  5. ❗️ 개선 전 (N+1 문제 발생)
  6. 🔧 개선 후 (fetch join 적용)
반응형

hanghae99-logo
항해99

 

이제 거의 실전 프로젝트가 마무리되어간다. 저번엔 Redis를 활용하여 수강신청의 성능을 개선해 봤는데, 이번에는 ORM에서 자주 발생하는 N+1 문제를 개선하였다. 문제가 발생하는 부분을 확인하고, 개선하는 작업을 진행하였다.

 


 

✔️ N+1 문제 발생

우리 프로젝트에서 N+1이 발생한 부분은 장바구니 페이지를 조회할 때 발생했다. 페이지 조회 시, 과목 정보에 대한 쿼리가 여러 번 요청되는 것을 확인하였다.

cart-imghibernate-img
장바구니 페이지 N+1 문제 발생으로 성능 저하 예상

 

 

💬 원인 분석

장바구니 페이지에서 N+1 문제가 발생하는 원인을 찾아보자. RegisteredSubjectRepository에서, findAllByStudentId() 메서드로 학생이 장바구니에 담은 과목들의 정보를 Spring Data JPA의 쿼리메서드로 불러오도록 되어있다.

 

[ RegisteredSubjectRepository.java ]


      
// RegisteredSubjectRepository - 해당하는 학생의 장바구니 정보 조회
List<RegisteredSubject> findAllByStudentId(Long studentId);

 

RegisteredSubject 엔티티 코드의 일부이다. findAllByStudentId()로 정보를 불러올 때, Student의 정보와 Subject의 정보가 @ManyToOne 연관관계로 매핑되어있다. @xxxToOne 관계는 기본으로 즉시 로딩(fetchType = EAGER)으로 설정된다. 

 

findById()와 같이 한 개를 조회하는 경우에는 하이버네이트가 join을 이용해서 쿼리 최적화를 해주지만, findAll() 메서드 같은 경우는 즉시로딩 이더라도 N+1 문제가 발생하게 된다.

 

그렇기 때문에, RegisteredSubject 엔티티에서 findAll()로 정보를 불러올 때, 해당하는 학생의 정보와 해당하는 과목의 쿼리가 추가적으로 N번 요청되고 있는 상황인 것이다.

[ RegisteredSubject.java ]

entity-img
학생, 과목 연관관계

 

✔️ 해결 및 개선

N번의 추가적인 쿼리를 개선하기 위하여 fetch join을 활용하였다. 과목 정보를 가져올 때, 연관된 학생의 정보와 과목의 정보를 한 번의 쿼리로 모두 가져오도록 개선하였다. 더 이상 연관관계에 대한 쿼리문이 요청되지 않고, 단 1개의 쿼리만 요청되는 것을 확인할 수 있었다.

fetch-join-query
fetch join 활용
hibernate
join-query
join으로 한 번에 관련 데이터를 가져온다

 

✔️ 성능 비교 테스트 결과 - 개선 전 vs  개선 후

성능이 얼마나 개선됐는지 확인하기 위해, 장바구니에 페이지에 Jmeter로 요청하여 응답시간을 비교해 보았다.

 

한 학생이 장바구니에 50개의 과목을 담아뒀다고 가정하고, 장바구니에 50개의 과목을 넣어두고 테스트를 진행했다. 장바구니 페이지에 총 10회 GET 요청을 보내서 평균값으로 결과를 비교하였다.

 

❗️ 개선 전 (N+1 문제 발생)

test-result1
N+1 개선 전

개선 전 10회 평균 응답시간 : 50ms

🔧 개선 후 (fetch join 적용)

test-result2
N+1 개선 후

개선 후 10회 평균 응답시간 : 34ms

 

결과적으로 10회 평균 응답 시간이 50ms -> 34ms로 약 32% 개선된 것을 확인 할 수 있었다.

반응형
저작자표시 비영리 변경금지 (새창열림)
  1. ✔️ N+1 문제 발생
  2. 💬 원인 분석
  3. ✔️ 해결 및 개선
  4. ✔️ 성능 비교 테스트 결과 - 개선 전 vs  개선 후
  5. ❗️ 개선 전 (N+1 문제 발생)
  6. 🔧 개선 후 (fetch join 적용)
'항해99 개발일지' 카테고리의 다른 글
  • 항해99 - 실전 프로젝트 4주차, Redis를 활용한 수강신청 성능 개선
  • 항해99 - 실전 프로젝트 3주차, 동시성 문제 발생 및 해결
  • 항해99 - 실전 프로젝트 2주차
  • 항해99 - 실전 프로젝트, 대규모 트래픽 챌린지 팀
꼼상
꼼상
프로그래밍 정보를 공유합니다
꼼상
개발서랍장
꼼상

Github
전체
오늘
어제
  • 분류 전체보기 (23)
    • 개인 프로젝트 (3)
    • 항해99 개발일지 (10)
    • Spring (4)
    • Spring Data (2)
    • Java (2)
    • DB (0)
    • 인프라 (1)
    • PHP (1)

블로그 메뉴

    공지사항

    인기 글

    태그

    • PHP환경변수
    • 회고
    • PHP환경변수설정
    • 자료구조
    • PHP다운로드
    • JPA
    • Spring Boot
    • fetch join
    • docker
    • N+1
    • 실전 프로젝트
    • 비관적 락
    • CI/CD
    • Spring Security
    • 단일 책임 원칙
    • Spring MVC
    • 알고리즘
    • 챌린지팀
    • Java
    • 낙관적 락
    • 대규모 트래픽 프로젝트
    • Spring Data JPA
    • 항해99
    • 최소 신장 트리
    • 대규모 트래픽
    • 웹 미니 프로젝트
    • 이진 탐색
    • github actions
    • N + 1
    • PHP다운

    최근 댓글

    최근 글

    hELLO · Designed By 정상우.v4.2.2
    꼼상
    항해99 - 실전 프로젝트, N+1 문제 성능 개선
    상단으로

    티스토리툴바

    개인정보

    • 티스토리 홈
    • 포럼
    • 로그인

    단축키

    내 블로그

    내 블로그 - 관리자 홈 전환
    Q
    Q
    새 글 쓰기
    W
    W

    블로그 게시글

    글 수정 (권한 있는 경우)
    E
    E
    댓글 영역으로 이동
    C
    C

    모든 영역

    이 페이지의 URL 복사
    S
    S
    맨 위로 이동
    T
    T
    티스토리 홈 이동
    H
    H
    단축키 안내
    Shift + /
    ⇧ + /

    * 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.