회고
@Query("SELECT t FROM Todo t LEFT JOIN FETCH t.user u ORDER BY t.modifiedAt DESC")
Page<Todo> findAllByOrderByModifiedAtDesc(Pageable pageable);
LEFT JOIN FETCH 를 통해 N+1 문제 해결@EntityGraph(attributePaths = "user")
Page<Todo> findAllByOrderByModifiedAtDesc(Pageable pageable);
@EntityGraph를 사용하여 N+1 해결FetchType.EAGER 로 조회 시 조회된 데이터(N)만큼 연관 관계에 대한 쿼리가 추가 발생하는 문제를 N+1 문제라고 함.
이를 FetchType.LAZY로 변경하여 해당 연관 관계가 필요한 시점에 조회하는 것으로 회피할 수 있지만 여전히 조회 시점에 N+1 조회 쿼리가 추가적으로 발생.
이 N+1 문제를 해결하기 위해서는?
1️⃣FETCH JOIN과 2️⃣@EntityGraph 방법을 사용할 수 있다.
지연로딩(LAZY)가 아닌 즉시로딩(EAGER)처럼 한번에 조회하여 프록시가 아닌 실제 엔티티 참조 가능.
attributePath 설정으로 간단하게 사용 가능Fetch Join이나 @EntityGraph나 기본적으로는 JPQL으로 JOIN하여 데이터를 가져오는 것이기 때문에 LIMIT, OFFSET을 사용하는 페이징 사용 시 경고가 뜬다
DB에서 처리가 되지 않고 모든 데이터를 메모리에 불러와서 메모리에서 페이징을 처리한다.
| Team ID | Member ID |
|---|---|
| 1 | 10 |
| 1 | 11 |
| 2 | 20 |
| 3 | 30 |
| 3 | 31 |
| 3 | 32 |
| 4 | 40 |
| 5 | 50 |
| 5 | 51 |
이 경우 메모리 부족 문제가 발생할 가능성이 큼! 그렇다면?
@BatchSize로 해결
일대다 관계에서 페치 조인을 했을 때 데이터 뻥튀기가 발생하는 것은 하이버네이트5 버전에서 객체-RDB의 간극 때문에 발생했던 문제인데, 하이버네이트6 이후부터는 JPA 쿼리에 distinct가 자동으로 적용됨
인터셉터 https://mangkyu.tistory.com/173
이번 과제는 내가 처음부터 코드를 작성하는 것이 아닌, 이미 만들어진 다른 사람의 코드를 보고 개선점/오류를 찾는 것이어서 문제 접근 방식이 달랐던 것 같다.