미소를뿌리는감자의 코딩
[Spring] JPA n+1 문제 본문
아직 내가 작성하는 코드에서 n+1 문제가 발생하진 않았지만, 흔하게 일어나는 문제인 만큼
이에 대해서 깊게 알아보고자 한다.
JPA n+1 문제는 왜 생기는걸까?
Java ORM 기술인 JPA를 사용하다보면 필수적으로 n+1문제를 맞닫뜨리게 됩니다. 내가 의도 하지않는 쿼리가 나가고 거기다 여러번 나간다면 정말 무섭겠죠. 왜 발생하고 어떻게 해결해 나가야 정리
jh2021.tistory.com
https://incheol-jung.gitbook.io/docs/q-and-a/spring/n+1#entitygraph
N+1 문제 | Incheol's TECH BLOG
JPA N+1 문제에 대해 알아보자
incheol-jung.gitbook.io
이분의 글을 보고 더 깊게 알아보았다. (감사합니다 (_ _) )
n+1의 주된 문제점은 쿼리가 여러번 날라간다는 점이다.
한 명의 집사가 10마리의 고양이를 키우고 이것이 @ManyToOne으로 묶게 된다면,
집사를 조회했을 때 연결 지어져 있는 10마리의 고양이를 조회하기 위해 집사의 수 만큼의 쿼리가 더 추가적으로 발생하게 된다.
owner가 한번 call하게 되면, owner와 연결된 cat을 부르기 위한 쿼리가 너무 많이 불러지게 된다.
이를 해결하기 위한 방법은 다음과 같다.
1. 즉시로딩
- Join Fetch
- @EntityGraph
2. 지연 로딩
- BatchSize : 연관된 엔티티를 접근할 떄 지정된 수만큼 엔티티를 한번의 쿼리로 불러올 수 있다.
* 단순히 FetchType.LAZY 로 한다고 해서 해결이 되지는 않는다. 고양이에 접근할 때, 10개의 쿼리가 실행되는 것은 동일하다.
[즉시 로딩 - Join Fetch ]
OwnerRepository에 다음과 같이 쿼리문을 작성해 준 후,
findAllJoinFetch를 해주었다.
하지만, assertFalse에서 error를 내뱉었고, 오랜시간 에러의 이유를 찾으려고 했지만 찾지 못했다 ㅜ
[즉시 로딩 - @EntityGraph ]
쿼리 수행 시 바로 가져올 path를 설정하여, eager로 수행될 수 있도록 하는 방법이다.
이번에는 위와 같이 설정한 후, findAllJoinFetch를 해주니, 에러도 내뱉지 않고, 쿼리도 하나의 쿼리로 실행됨을 확인할 수 있었다.
[ 지연 로딩 - Batch Size ]
@BatchSize를 5로 결정한 후, findAll()을 수행한 결과는 다음과 같다.
사이즈를 설정한 만큼, in절을 묶어서 보내는 것을 의미한다.
이는 ORM 에서 성능 최적화를 위해 사용된다.
연관된 엔티티를 로딩할 때 지정된 크기의 배치로 데이터를 가지고 오는 것이다.
즉, 연관된 엔티티를 한 번에 하나씩 가져오는 대신 지정된 크기의 배치로 묶어서 가져옴으로써 데이터베이스와의 통신 횟수를 줄이고 성능을 향상시키는 기법이다.
batch size = 5 는 5개씩 묶어서 가져오는 것.
현재 EAGER로 설정해서, 위와 같이 5개가 묶어서 옴을 확인할 수 있다.
만약 .LAZY로 설정하게 된다면,
Hibernate: select o1_0.id, o1_0.name from owner o1_0
만 출력됨을 확인할 수 있다. LAZY 이므로 사용될 때까지 아직 5개를 묶어서 가져오지 않았음을 확인할 수 있다.
< 요약 >
만약 집사 10명, 각각의 집사에 10마리의 고양이가 join되어 있다고 할 때,
10번의 쿼리가 더 나가게 된다.
즉 10명의 집사와 연관되어 있는 무언가가 있다면, (고양이 마리의 개수는 상관이 없다) 연관된 무언가를 조회하기 위해 10번의 쿼리가 더 나가게 된다.
그렇다면 왜 10 + 10 이 아니라, 1+n, n+1 이라고 하는 것일까?
1은 초기 쿼리를 실행하는 데 필요한 쿼리 수를 의미한다.
이 초기 쿼리는 보통 어떤 엔티티의 컬렉션을 가져오기 위해 실행되는 것이므로, 1이라고 한다.
'강의수강 > [Spring]' 카테고리의 다른 글
[Spring] 도커를 이용한 배포 (0) | 2024.04.03 |
---|---|
[Spring] S3 이용 - 이미지 등록, 조회 하기 (1) | 2024.03.22 |
[Spring] @Transactional, 격리 수준, 데드락 (0) | 2024.03.10 |
[Spring] HTTP Method: GET, PUT, POST, DELETE, PATH (REST API) (0) | 2024.03.09 |
[Spring] intellij 에서 모든 파일이 .java로 바뀌어 인식이 안될 때 (Java file outside of source root intelliJ) (1) | 2024.03.08 |