Home MBTI별 선호 웹툰 조회 시 발생한 N+1 문제
Post
Cancel

MBTI별 선호 웹툰 조회 시 발생한 N+1 문제

이번엔 N+1 문제가 발생할 것을 알고도 한 번 어느정도 차이가 있는 지 보기 위해 그냥 실행시켜본 N+1 문제를 보려고 한다.

문제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Entity  
@Getter  
@NoArgsConstructor  
public class MbtiWebtoon extends BaseEntity {  
  
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)  
    private Long id;  
  
    @ManyToOne  
    @JoinColumn(name = "mbti_id")  
    private Mbti mbti;  
  
    @ManyToOne  
    @JoinColumn(name = "webtoon_id")  
    private Webtoon webtoon;  
  
    @Builder  
    public MbtiWebtoon(Mbti mbti, Webtoon webtoon) {  
	    this.mbti = mbti;  
        this.webtoon = webtoon;  
    }  
}
  • MBTI별 선호 웹툰의 목록을 담는 엔티티이다.
  • 홈에 각 MBTI별로 선호웹툰들이 약 20개 정도 존재하고 해당 웹툰들이 한 번에 조회된다.
1
2
3
4
public interface MbtiWebtoonRepository extends JpaRepository<MbtiWebtoon, Long> {  
   
    List<MbtiWebtoon> findByMbti(Mbti mbti);  
}
  • 처음에 이렇게 작성하고 DTO로 변환하는 로직을 작성하던 중 N+1 문제가 일어날 것임을 알았다.
    • 하지만 실제로 쿼리가 어떻게 발생하는지, 그리고 그에 따른 성능 차이는 얼마나 될 지 궁금해서 그냥 실행해보게 되었다.
  • 여기서 나타나는 N+1문제는 MbtiWebtoon 엔티티의 Webtoon이 지연로딩 설정되어 있기 때문에 해당 Webtoon에 대한 정보를 얻으려 할 때 각각의 Webtoon에 대한 조회 쿼리가 발생하는 문제이다.

즉 MBTI 가지 수 16가지 * 약 20의 최소 320번 이상의 쿼리가 발생하는 것이다.

해결

페치 조인을 사용해 웹툰 정보를 쿼리 한 번으로 가져오도록 하였다.

1
2
3
4
5
public interface MbtiWebtoonRepository extends JpaRepository<MbtiWebtoon, Long> {  
  
    @Query("select mw from MbtiWebtoon mw join fetch mw.webtoon where mw.mbti = :mbti")  
    List<MbtiWebtoon> findByMbti(@Param("mbti") Mbti mbti);  
}

결과

  • N+1 문제 해결 전

  • N+1 문제 해결 후

  • 약 37% 정도의 성능 개선을 볼 수 있었다. (한 가지 MBTI에 대한 요청)
  • 만약 조회하는 Webtoon의 수가 더 컸다면 차이가 더 컸을 것이라고 생각한다.

쿼리도 무수히 많은 select 쿼리에서 단 하나의 쿼리만 발생하는 것을 볼 수 있다.

This post is licensed under CC BY 4.0 by the author.

추천 알고리즘에서의 update 쿼리 N+1 문제

Java로 구현하는 개인화 웹툰 추천 알고리즘 with apache commons math