You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
연관관계 엔티티를 함께 조회할 때, JPQL(em.createQuery("select m from Member m"))을 사용하는 경우 즉시로딩이나 지연 로딩에 대해 신경쓰지 않고 SQL문 실행. 연관된 컬렉션이 즉시 로딩이므로 엔티티를 가져오기 위해 SQL문이 즉시 실행된다
지연 로딩 N + 1
JPQL에서는 발생하지 않느다. 하지만 비즈니스 로직에서 실제 하위 컬렉션(엔티티)을 사용하면 지연 로딩이 발생한다. 값을 초기화하는 수만큼 SQL문이 실행된다
해결 방법
페치 조인
가장 일반적인 방법
inner join 문을 생성
단점:
Inner Join 문으로 카테시안 곱(Cartesian Product) 발생하여 중복된 결과가 조회될 수 있다.
중복을 제거하기 위해 DISTINCT를 사용
불필요한 쿼리문이 추가될 수 있다.
어떤 필드는 Eager 조회, 어떤 필드는 Lazy 조회까지 쿼리에서 표현해야한다.
@EntityGraph
attributePaths에 쿼리 수행시 바로 가져올 필드명을 지정하면 Lazy가 아닌 Eager 조회
Outer Join문을 문으로 카테시안 곱(Cartesian Product) 발생하여 중복된 결과가 조회될 수 있다.
하이버네이트 @BatchSize
연관된 엔티티를 조회할 때 지정한 size 만큼 SQL의 IN 절을 사용해서 조회
(조회 가능한 데이터 / size) 수 만큼 SQL이 실행
즉시 로딩으로 설정하면 SQL 문이 모두 한번에 실행되지만, 지연 로딩의 경우 다음 데이터가 필요한 시점에 SQL 쿼리가 추가로 실행된다.
하이버네이트 @Fetch(FetchMode.SUBSELECT)
연관된 데이터를 조회할 때 서브쿼리를 사용해서 N + 1 문제를 해결
카테시안 곱 해결 방법
일대다 필드의 타입을 Set으로 선언
Set은 중복을 허용하지 않는 자료구조이므로 중복등록이 불가
LinkedHashSet을 사용하여 순서 보장
JPQL DISTINCT 키워드로 중복을 제거
Set보다 List를 써야하는 경우 사용하자
정리
즉시 로딩 전략은 그럴듯 보이지만 N + 1 문제는 물론이고 비즈니스 로직에 따라 필요하지 않은 엔티티가 로딩되는 상황이 자주 발생한다
즉시 로딩의 가장 큰 문제는 성능 최적화가 어렵다는 점이다.
엔티티를 조회하다보면 즉시로딩이 연속으로 발생해서 전혀 예상하지 못한 SQL이 실행될 수 있다.
따라서 모두 지연로딩으로 설정하고 성능 최적화가 필요한 곳에 JPQL 페치 조인을 사용하자
N + 1 문제란
처음 실행한 SQL의 결과 수 만큼 추가로 SQL 쿼리가 실행되는 문제
em.createQuery("select m from Member m")
)을 사용하는 경우 즉시로딩이나 지연 로딩에 대해 신경쓰지 않고 SQL문 실행. 연관된 컬렉션이 즉시 로딩이므로 엔티티를 가져오기 위해 SQL문이 즉시 실행된다해결 방법
@EntityGraph
attributePaths
에 쿼리 수행시 바로 가져올 필드명을 지정하면 Lazy가 아닌 Eager 조회@BatchSize
@Fetch(FetchMode.SUBSELECT)
카테시안 곱 해결 방법
Set
으로 선언DISTINCT
키워드로 중복을 제거정리
@OneToOne
,@ManyToOne
: 기본 페치 전략은 즉시 로딩@OneToMany
,@ManyToMany
: 기본 페치 전략은 지연 로딩XXXToOne
은 LAZY로 설정해서 지연로딩 전략을 사용하자Ref.
[책] 자바 ORM 표준 JPA 프로그래밍
[기억보단기록을 - JPA N+1 문제 및 해결방안]
The text was updated successfully, but these errors were encountered: