JPA N+1 문제

김진회·2022년 11월 22일
0

jpa

목록 보기
2/5

1. N+1문제란?

연관 관계에서 발생하는 이슈로 연관 관계가 설정된 엔티티를 조회할 경우, 조회된 데이터 갯수 만큼 연관관계의 조회 쿼리가 추가로 발생하여 데이터를 읽어오는 현상


2. 발생 이유

jpaRepository에 정의한 인터페이스 메서드를 실행 시, JPA는 메서드 이름을 분석해서 JPQL을 생성하고 실행한다. 이 때, 연관관계를 무시하고 해당 엔티티 기준으로 쿼리를 조회한다. 만약 연관된 엔티티 데이터가 필요한 경우, 지정한 FetchType 시점에 조회를 별도로 호출하게 된다.

FetchType.EAGER (즉시 로딩)

jpaRepository 인터페이스 메소드 실행 시, 바로 N+1문제 발생

FetchType.LAZY (지연 로딩)

jpaRepository 인터페이스 메소드 실행 시에는 문제가 없지만 연관된 데이터를 사용하려 할 때 N+1문제 발생

👉 즉, 발생 시점이 다른 것이지 지연 로딩이 N+1문제를 해결하는 것은 아니다!


3. 해결 방법

1) Fetch Join

  • JPQL을 사용하여 fetch join을 작성해서 사용한다.
    ex) @Query("select c from Company c join fetch c.employee")
  • 별도의 지정이 없다면 join fetch 구문은 JPQL에 의해 inner join 구문으로 변경되어 실행된다.

2) @EntityGraph

  • 어노테이션을 이용해서 fetch 조인을 하는 방법.
  • 동일하게 JPQL을 작성하고 @EntityGraph에 필요한 연관관계를 설정한다.
  • outer join으로 실행된다. 따라서 카테시안 곱이 발생해서 중복 데이터가 존재할 수 있다.
    때문에 이 방식은 추천하지 않는다.

3) Batch Size

  • jpa의 application.yml(properties)에 batch_size를 지정해주거나 어노테이션을 이용하면 SQL의 IN절을 사용해 여러 번 일어날 N+1문제를 1번만 발생하도록 한다.
    결국 동일하게 N+1문제가 발생하긴 한다.

4) QueryBuilder

  • Mybatis, 쿼리DSL과 같은 같은 쿼리빌더 플러그인을 이용하여 최적화된 쿼리를 구현할 수 있다.

4. 실무에서의 N+1문제 해결

연관 관계에 대한 설정은 모두 FetchType.LAZY(지연로딩)을 사용하고, 추가로 성능 최적화가 필요한 부분은 FetchJoin이나 QueryBuilder(추천)을 같이 사용하자!

참조

https://incheol-jung.gitbook.io/docs/q-and-a/spring/n+1
https://programmer93.tistory.com/83

profile
SSAFY 7기. HMG. 협업, 소통, 사용자중심

0개의 댓글