GiYeong

N + 1 문제 본문

CS/JPA

N + 1 문제

gy2710 2022. 8. 31. 17:49

N + 1 문제

연관 관계가 설정되어있는 엔티티를 조회할 때, 조회된 데이터의 개수(N개)만큼 연관 관계의 조회 쿼리가 추가적으로 발생하여 데이터를 읽어오는 현상

 

원인

JPA가 JPQL을 분석하여 SQL을 생성할 때, 글로벌 Fetch 전략을 참고하지 않고 JPQL 자체만을 사용하기 때문에

 

Fetch 전략이 즉시 로딩(Eager)일 경우

  1. findall() 이 발생하면 [select * from A] 과 같은 JPQL 구문 및 이를 분석하여 생성된 SQL이 실행됨
  2. DB의 결과를 받아 엔티티(A)의 인스턴스들이 생성됨
  3. 생성된 엔티티와 연관되어있는 다른 엔티티(B)도 로딩됨
  4. 영속성 컨텍스트에 연관되어있는 다른 엔티티(B)가 있는지 확인
  5. 영속성 컨텍스트에 없다면 2단계에서 생성된 인스턴스들의 개수와 맞게 [select * from B where A=?] 와 같은 SQL이 실행됨 ( N + 1 발생 )

Fetch 전략이 지연 로딩(Lazy)일 경우

  1. findall() 이 발생하면 [select * from A] 과 같은 JPQL 구문 및 이를 분석하여 생성된 SQL이 실행됨
  2. DB의 결과를 받아 엔티티(A)의 인스턴스들이 생성됨
  3. 코드 중에 A 엔티티와 연관되어있는 B 엔티티의 객체를 사용하려는 시점에서 영속성 컨텍스트에서 이를 확인
  4. 영속성 컨텍스트에 없다면 2단계에서 생성된 인스턴스들의 개수와 맞게 [select * from B where A=?] 와 같은 SQL이 실행됨 ( N + 1 발생 )

 

해결방법

Fetch Join

JPQL을 사용하여 DB에서 데이터를 가져올 때, 처음부터 연관된 데이터까지 같이 가져오는 방식

 

EntityGraph 어노테이션(권장되지 않음)

@EntityGraph 어노테이션을 통한 Fetch Join

 

 Batch Size

N + 1 문제가 발생하더라도 N + 1 문제를 1번만 더 조회하는 방식을 통해 성능을 최적화

 

실무에서 N + 1 문제를 방지하는 방법

연관관계에 대한 설정이 필요하다면 지연 로딩(Lazy)모드를 사용하고, 성능 최적화가 필요한 부분에서는 Fetch Join을 사용한다. 또한 기본적으로 Batch Size의 값을 1000이하로 설정한다.(대부분의 DB에서 IN 절의 최대 개수 값이 1000이기 때문)

'CS > JPA' 카테고리의 다른 글

JPA 영속성 컨텍스트  (0) 2022.08.31
JPA  (0) 2022.07.19
ORM  (0) 2022.07.19
Comments