N+1 문제
FetchType.EAGER를 필요한 곳에서 Lazy Loading으로 쿼리가 실행될 때 발생하는 문제
↓ Lazy Loading vs Eager Loading
더보기
Lazy Loading (지연된 로딩)
: 필요 시점까지 객체의 초기화를 연기시키기 위해 컴퓨터 프로그래밍에 흔히 사용되는 디자인 패턴
- 페이지를 불러올 때 당장 필요하지 않은 리소스들을 나중에 로딩
(사용자가 보지 않는 것들은 나중에 로딩) - Lazy Loading으로 설정되어 있는 엔티티는 프록시 객체로 불러와짐
- 사용자가 필요로 하는 시점에 로딩
- 콘텐츠의 제공 속도가 빠름
- (예시) 무한 스크롤 사용 시 - 사용자의 스크롤 깊이를 계산하다가 페이지 끝에 도달했을 때 데이터를 요청
Eager Loading (즉시 로딩)
: 조인을 사용하여 SQL을 한번에 조회
- select 쿼리를 여러번 수행해서 엔티티 조회
- join 사용
- 네트워크 콘텐츠가 접근되고 초기화 시간을 최소로 유지해야 하는 상황에서 이상적
발생 상황
1. Join Fetch 사용
@Query("select u from User u join fetch u.chat")
@Query("select u from User u join fetch u.chat c join fetch c.title")
- inner join 발생
- 불필요한 쿼리문이 추가됨
2. Entity Graph
@EntityGraph(attributePaths = "chat")
@Query("select u from User u")
List<User> findAllEntityGraph();
@EntityGraph(attributePaths = {"chat", "chat.title"})
@Query("select u from User u")
List<User> findAllEntityGraphWithTitle();
- attributePaths에 쿼리를 수행할 때 바로 가져올 필드명일 지정하면 Eager 로딩으로 조회
해결 방안
1. Set 필드 타입 선언
- 일대다 필드의 타입을 Set으로 선언 → 중복 방지
- 순서를 보장하려면 LinkedHashSet 사용
@OnteToMany(cascade = CascadeType.ALL)
@JoinColumn(name = "user_seq")
private Set<Chat> chats = new LinkedHashSet<>();
2. distinct 사용
@Query("select DISTINCT u from User u join fetch u.chat c join fetch c.title")
[ 출처 ]
https://ko.wikipedia.org/wiki/%EC%A7%80%EC%97%B0%EB%90%9C_%EB%A1%9C%EB%94%A9
'TIL > JPA' 카테고리의 다른 글
[JPA] 데이터베이스 스키마 자동 생성하는 방법 (0) | 2022.05.07 |
---|---|
[JPA] annotation 종류 (0) | 2022.05.06 |
[JPA] Querydsl 설정 (0) | 2022.04.19 |
[JPA] JPA란? (0) | 2022.04.19 |