JPA N+1
상황
1. Post(게시글) 엔티티가 있고, 그 안에 author(작성자)로 User를 참조.(N:1 관계)
2. postRepository.findAll()로 게시글 목록 10개를 가져옴.
3. 그 후, 각 Post에서 post.getAuthor().getName() 같은 걸 화면에 보여주려고 접근
쿼리
1. 게시글 목록 가져오는 쿼리 1번
SELECT * FROM posts;
2. 첫 번째 글의 author를 가져오는 쿼리 1번
SELECT * FROM users WHERE id = ?;
3. 두 번째 글의 author를 가져오는 쿼리 또 1번
4. 세 번째 글의 author를 가져오는 쿼리 또 1번
… 이렇게 N번
결과적으로 : 목록 한 번(N개) 가져왔는데, 연관된 데이터를 N번 추가로 찍어서 총 N+1번의 쿼리" → N+1 문제
N+1이 나타나는 곳


postService.findAll() → posts 전체 가져오는 1번 쿼리
Response에서 post.getAuthor().getName() -> post마다 author를 Lazy 로딩하면서 쿼리 추가 → N번
= N + 1
실제로 확인해보기
/api/posts 수행 후 아래와 같은 sql 쿼리문을 확인할 수 있다.
1) 첫 쿼리 : posts 전체 가져옴
select
p1_0.id,
p1_0.author_id,
p1_0.content,
p1_0.created_at,
p1_0.title,
p1_0.updated_at
from
posts p1_0
2) 같은 형태의 쿼리가 여러번 반복 실행
select
u1_0.id,
u1_0.created_at,
u1_0.email,
u1_0.name,
u1_0.status,
u1_0.updated_at
from
users u1_0
where
u1_0.id=?
문제 발생 원인
JPA 기본 fetch 전략 : FetchType.LAZY (필요할 때만 불러오기)
"필요할 때" 반복문이 돌면서 여러 번 필요해지므로 N + 1 문제가 발생.
해결
record 형태로 바꾸기
record : 모든 필드를 private final로 만듦, 생성자, getter, equals(), hashCode(), toString() 전부 만들어줌. -> immuatable 데이터 묶음으로 만들어줌.


결과
600줄 이상이던 쿼리가 아래 사진의 크기로 대폭 감소함을 알 수 있다.

추가 학습
사실 Fetch Join도 많이 쓰는데, 시간 관계상 여기서 한번 끊고 다음에 해보려고 한다. 그리고 하나만 하기엔 아쉬우니까 Page 처리도 같이 포함해서 해보려고 한다.
'WEB programming > back-end' 카테고리의 다른 글
| [UMC] 1주차 정리 & 느낀점 (1) | 2022.03.21 |
|---|