N + 1 문제란?
1번의 조회 쿼리를 Db에 요청했음에도 N번의 추가적인 조회요청이 전송되는 것을 말한다.
원인?
주로 JPA와 JPQL 동작 특성 때문에 N+1 문제가 발생한다.
- JPA Repository를 활용해 인터페이스 메소드를 호출 할 때(Read 시) 발생하며 1:N 또는 N:1 관계를 가진 엔티티를 조회할 때 발생 한다.
- JPA Repository로 find 시 실행하는 첫 쿼리에서 하위 엔티티까지 한 번에 가져오지 않고,
하위 엔티티를 사용할 때 추가로 조회하기 때문에 발생 한다.
- JPQL은 기본적으로 글로벌 Fetch 전략을 무시하고 JPQL만 가지고 SQL을 생성하기 때문에 발생한다.
언제?
즉시 로딩
JPA Fetch 전략(Fetch Type)이 EAGER (즉시 로딩) 전략으로 데이터를 조회하는 경우
- EAGER의 경우이후 JPA에서 Fetch 전략을 가지고 (여기서는 즉시 로딩) 해당 데이터의 연관 관계인 하위 엔티티들 을 추가 조회(LAZY - 지연 로딩 발생) 된다.
- 유저만 조회할 때 유저(EAGER) , 댓글(EAGER) 경우 유저를 찾고 유저의 댓글에 EAGER를 확인 유저의 모든 댓글 까지 가져오게 된다.
결론
즉시로딩은 Jpql로 전달되는 과정에서 Jpql 후 Eager 감지로 인한 N쿼리가 추가로 발생하는 경우가 있기 때문에 자주 안쓰는게 좋다.
지연 로딩
JPA Fetch 전략(Fetch Type)이 LAZY (지연 로딩) 전략으로, 전체 데이터를 가져온 이후 연관 관계인 하위 엔티티를 사용할 때 다시 조회하는 경우 주로 발생한다.
- Lazy의 경우 JPA에서 Fetch 전략을 가지지만, 여기서는 지연 로딩이기 때문에 추가 조회는 하지 않는다.
하지만, 하위 엔티티를 가지고 작업하게 되면 추가 조회하기 때문에 결국 N+1 문제가 발생한다.
- user를 사용할 때 한번 불러오고 user.Comment() 할 때 한번 더 불러오는 현상이 발생한다.
- 사용하는 시점에 불렀으니 사용하는 시점에 부른 후에 또 사용하려면 한번 더 불러야 한다.
해결
- 즉시 로딩 → 지연 로딩으로 변경한다.
- 지연 로딩 → distnict를 사용해 user가 여러번 생성되지 않게 막고, fetch join을 사용하여 지연 로딩이 걸려있는 연관관계 에 대해서 한번에 같이 즉시 로딩 하게 한다. ( 한번 더 불러올 필요가 없도록 만듦)
- fetch join : 한번에 연관관계의 모든 데이터를 로딩한다.
- @EntityGraph (attributePaths = {"articles"}, type = EntityGraphType.FETCH)
'TIL' 카테고리의 다른 글
WebSocket을 사용해 게임 플레이어의 실시간 방 참여를 활성화 하기 (0) | 2023.01.30 |
---|---|
Mybatis의 장점, 단점 Jpa의 장점, 단점 (0) | 2023.01.27 |
Java SSL 인증서 파일 등록 하는법 정리(Keytool, Portecle 이용) (0) | 2023.01.26 |
RDS - MySQL (0) | 2023.01.07 |
2023-01-03 Today I learned Oauth (0) | 2023.01.03 |
2022-12-14 ubuntu 시간 재설정 (0) | 2022.12.14 |
배달프렌드 사용자 분석 (0) | 2022.12.10 |
2022-12-06 today- I learned (0) | 2022.12.06 |