ORM/JPA

N+1 문제

잔망루피 2022. 10. 27. 21:32
반응형

N+1 문제

처음 실행한 SQL의 결과 수만큼 SQL을 더 실행한다.

 

 

즉시 로딩과 N+1

JPQL을 실행하면 JPA가 즉시 로딩/지연 로딩에 대해 신경쓰지 않고 SQL을 생성한다.

회원댓글 1:N 양방향 연관관계라면, 회원을 조회했을 때 댓글도 조회된다.

조회하는 회원이 많으면 댓글도 그만큼 조회된다.

SELECT * FROM MEMBER;
SELECT * FROM COMMENTS WHERE MEMBER_ID=1;
SELECT * FROM COMMENTS WHERE MEMBER_ID=2;
SELECT * FROM COMMENTS WHERE MEMBER_ID=3;

 

 

지연 로딩과 N+1

즉시 로딩과 다르게 JPQL에서 N+1 문제가 발생하지 않는다.

회원 댓글 1:N 양방향 연관관계라면, 모든 회원에 대해 연관된 댓글 컬렉션을 사용할 때 N+1 문제가 발생

 

 

N+1문제를 해결하는 방법

  1. 페치 조인 사용
  2. 하이버네이트가 제공하는 @BatchSize 어노테이션 사용
  3. 하이버네이트가 제공하는 @Fetch(FetchMode.SUBSELECT)

 

페치 조인 가장 일반적인 방법

SQL 조인을 사용해서 연관된 엔티티를 함께 조회

일대다 조인을 하면 중복된 결과가 나타날 수 있다. ➡️ JPQL의 DISTINCT를 사용해서 중복 제거
@BatchSize 연관된 엔티티를 조회할 때 지정한 size만큼 SQL의 IN 절을 이요해서 조회

ex) 즉시 로딩은 조회한 회원이 10명인데 size가 5라면 2번의 SELECT * FROM COMMENTS WHERE MEMBER_ID IN (?, ?, ?, ?, ?); 실행 

지연 로딩은 5건의 데이터를 미리 로딩 후 6번 째 데이터를 사용하면 SELECT * FROM COMMENTS WHERE MEMBER_ID IN (?, ?, ?, ?, ?);를 추가로 실행
@Fetch(FetchMode.SUBSELECT) 연관된 데이터를 조회할 때 서브 쿼리를 사용

ex) select m from Member m where m.id > 10

즉시 로딩으로 설정하면 조회 시점에 SELECT C FROM COMMENTS C WHERE C.MEMBER_ID IN(SELECT M.ID FROM MEMBER M WHERE M.ID > 10);

지연 로딩으로 설정하면 지연 로딩된 엔티티를 사용하는 시점에 SELECT C FROM COMMENTS C WHERE C.MEMBER_ID IN(SELECT M.ID FROM MEMBER M WHERE M.ID > 10);이 실행된다.

 

 

🔥 결론

  • 지연 로딩만 사용하는 것을 추천!!!
    • 기본값이 즉시 로딩인 @OneToOne, @ManyToOne은 fetch=FetchType.LAZY로 설정하면 된다.
  • 즉시 로딩의 가장 큰 문제는 성능 최적화가 어렵다.
  • 성능 최적화가 꼭 필요한 곳에는 JPQL 페치 조인을 사용하자.

 

 

참고 👉 자바 ORM 표준 JPA 프로그래밍

반응형

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

[JPA] OneToOne  (1) 2024.03.17
[Error] org.hibernate.LazyInitializationException: could not initialize proxy  (0) 2022.07.20
@JoinColumn  (0) 2022.05.19
변경 감지(Dirty Checking)  (0) 2022.05.18
JPA를 이용한 데이터베이스 초기화  (0) 2022.03.31