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문제를 해결하는 방법
- 페치 조인 사용
- 하이버네이트가 제공하는 @BatchSize 어노테이션 사용
- 하이버네이트가 제공하는 @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 |