-
JPA 지연로딩 사용시 N+1 문제Spring/스프링가링가링 2022. 10. 6. 15:07
< 주제 >
JPA 지연로딩 사용시 N+ 1 문제
ORM - JPA, Spring Data JPA
Embedded Database를 활용한 JPA test
JPA 모든 N+1 발생 케이스과 해결책 (velog.io)
JPA 모든 N+1 발생 케이스과 해결책
N+1이 발생하는 모든 케이스 (즉시로딩, 지연로딩)에서의 해결책과 그 해결책에서의 문제를 해결하는 방법에 대해 이야기 하려합니다 😀
velog.io
JPA N + 1 문제 발생 이유
객체에 대해서 조회한다고 해도 다양한 연관관계들이 매핑에 의해서 관계가 맺어진 다른 객체가 함께 조회되는 경우에 N+1이 발생
=> 지연로딩 사용 (연관된 객체를 사용하는 시점에 로딩)
데이터를 처음 조회한 시점에서는 N + 1 문제가 발생하지 않음
하지만, 하위 엔티티를 사용하게 되면 추가 조회가 이때 발생하게 되면서 N + 1 문제가 발생함
[JPA] N+1 문제 원인 및 해결방법 알아보기 — 슬기로운 개발생활 (tistory.com)
[JPA] N+1 문제 원인 및 해결방법 알아보기
JPA를 사용하면 자주 만나게 되는 것이 N + 1 문제이다. N + 1 문제는 성능에 큰 영향을 줄 수 있기 때문에 N + 1 문제가 무엇이고 어떤 상황에 발생되는지, 어떻게 해결하면 되는지에 대해 알아보고
dev-coco.tistory.com
해결 방법
1. Fetch Join
미리 두 테이블을 JOIN 해서 한 번에 모든 데이터를 탐색하면 N+1의 문제가 발생하지 않을 것이라는 생각에서 나온 방법
=> 연관된 두 테이블을 JOIN하는 쿼리를 직접 작성하는 것
내부 조인 (inner join)을 함
@Query("select DISTINCT o from Owner o join fetch o.pets") List<Owner> findAllJoinFetch();
Fetch Join의 단점
모든 데이터를 한 번에 가져오기 때문에 JPA가 제공하는 Pageable를 사용하지 못 함
1:N의 관계가 두 개 이상인 경우 사용 불가
패치 조인 대상에게 별칭 부여 불가능
2. @EntityGraph
attributePaths에 같이 조회할 연관된 엔티티명을 적으면 됨 (여러개도 가능)
1번 Fetch Join과 마찬가지로 Query문 작성 필요
외부조인(outer join)을 함
@EntityGraph(attributePaths = {"pets"}) @Query("select DISTINCT o from Owner o") List<Owner> findAllEntityGraph();
위의 두 방법은 모두 카테시안 곱이 발생하여 중복이 생길 수 있다.*카테시안 곱
Form절에 2개 이상의 Table이 있을 때, 두 Table 사이에 유효 join 조건을 적지 않았을 때 해당 테이블에 대한 모든 데이터를 전부 결합하여 Table에 존재하는 행 개수를 곱한 만큼의 결과값이 반환되는 것
[SQL] 카테시안 곱(Cartesian Product)이란? (tistory.com)
해결 방법
1. JPQL에 DISTINCT 를 추가하여 중복 제거
@Query("select DISTINCT o from Owner o join fetch o.pets") List<Owner> findAllJoinFetch(); @EntityGraph(attributePaths = {"pets"}) @Query("select DISTINCT o from Owner o") List<Owner> findAllEntityGraph();
2. OneToMany 필드 타입을 Set으로 선언하여 중복 제거@OneToMany(mappedBy = "owner", fetch = FetchType.EAGER) private Set<Pet> pets = new LinkedHashSet<>();
=> 순서 보장이 필요한 경우는 LinkedHashSet 사용