출처: 자바 ORM 표준 JPA 프로그래밍
N + 1 문제
N + 1 문제는 내가 예상했던 것보다 훨씬 많은 쿼리가 나가는 문제를 뜻한다.
여기서 1은 내가 예상한 (당장 보이는) 하나의 쿼리이고,
N은 데이터의 개수 N만큼 발생하는 예상치 못한 쿼리이다.
다양한 예시
Member 엔티티와 Team 엔티티가 있다고 가정하자.
이들은 다대일 관계이며,
Member에서 Team을 참조할수있다.
이런 상황에서 Member를 조회해보자.
1. em.find()로 조회
연관관계 매핑 시, 즉시 로딩으로 했는지, 지연 로딩으로 했는지가 중요하다.
즉시 로딩으로 설정시, 쿼리가 나갈때 즉시 로딩으로 설정된 엔티티들을 전부 조인해서 가져온다.
지연로딩으로 설정시, 쿼리가 나갈때 일단은 조회한 엔티티 자체만 가져온다.
= JPQL 사용시 발생하는 N + 1 문제와 크게 관련이 없다.
2. JPQL로 조회 - 즉시 로딩
JPQL 쿼리: select m from Member m
이렇게 해도 JPQL은 어쩔수없이 SQL로 번역이 되는거기에,
실제로는 그저 멤버를 조회하는 쿼리만 나간다.
하지만 그렇게 데이터를 얻어오고 보니까 Team이 있고,
즉시 로딩으로 설정 되어 있기에 즉시 Team을 멤버 하나하나 각각 조회하는 쿼리가 나간다.
= N + 1 문제가 발생한다.
3. JPQL로 조회 - 지연 로딩
JPQL 쿼리: select m from Member m
이렇게 해도 JPQL은 어쩔수없이 SQL로 번역이 되는거기에,
실제로는 그저 멤버를 조회하는 쿼리만 나간다.
하지만 그렇게 데이터를 얻어오고 보니까 Team이 있고,
지연 로딩으로 설정 되어 있기에 일단 프록시 객체를 조회하고, 실제 조회는 나중으로 미룬다
하지만 나중으로 미뤘을 뿐이지, 결국은 Team을 사용시(조회 시) DB에 쿼리가 나가야한다.
즉시는 아니지만 나중에는 결국 Team을 멤버 하나하나 각각 조회하는 쿼리가 나간다.
= N + 1 문제가 발생한다.
4. JPQL로 조회 - 패치 조인 사용
즉시로딩, 지연로딩과 상관이 없다.
2,3 번의 경우를 해결하기 위한 것이다.
JPQL 쿼리: select m from Member m join fetch m.team
이렇게 하면 처음 실제로 나가는 쿼리가 Member, Team을 한번에 조회하는 쿼리이다.
실제 쿼리: select m.*, t.* from member join team ...
= N + 1 문제가 발생하지 않는다.
'Dev > JPA' 카테고리의 다른 글
JPA와 트랜잭션, 락 (0) | 2023.03.15 |
---|---|
API 설계시 DTO를 주고받아야 한다. 엔티티 말고 (0) | 2021.06.29 |
[강의정리] 값 타입 (0) | 2021.05.21 |
[강의정리] 영속성 전이, 고아객체, 생명주기 (0) | 2021.05.18 |
[강의정리] 프록시와 연관관계 관리 (0) | 2021.05.18 |