JVM/JPA

N+1 문제

kyoulho 2023. 7. 4. 19:17

N+1 문제

연관된 엔티티를 조회할 때 SQL문이 실행되는 것을 N+1 문제라고 한다.

즉시 로딩을 사용할 때도 JPQL은 JPQL만 사용해서 SQL을 생성하기에 N+1 문제가 발생할 수 있다.

모두 지연 로딩으로 설정하고 성능 최적화가 꼭 필요한 곳에는 JPQL 페치 조인을 사용하자.

 

페치 조인 사용

N+1 문제를 해결하는 가장 일반적인 방법은 페치 조인을 사용하는 것이다.

이때 조심해야 할 것은 일대다 조인일 경우 중복된 결과가 나타날 수 있으므로 JPQL의 DISTINCT를 사용해서 중복을 제거하는 것이다.

 

하이버네이트 @BatchSize

연관된 엔티티를 조회할 때 지정한 size만큼 SQL의 IN 절을 사용해서 조회한다. 만약 조회한 회원이 10명인데 size=5로 지정하면 2번의 SQL만 추가로 실행한다.

즉시 로딩으로 설정하면 조회 시점에 10건의 데이터를 모두 조회해야 하므로 다음 SQL이 두 번 실행된다. 지연 로딩으로 설정하면 지연 로딩된 엔티티를 최초 사용하는 시점에 다음 SQL을 실행해서 5건의 데이터를 미리 로딩해 둔다. 그리고 6번째 데이터를 사용하면 다음 SQL을 추가로 실행한다.

hibernate.default_batch_fetch_size 속성을 사용하면 애플리케이션 전체에 기본으로 @BatchSize를 적용할 수 있다.

@Entity
public class Member {
	
    @BatchSize(size = 5)
    @OneToMany(mappedBy = "member", fetch = FetchType.EAGER)
    private List<Order> orders = new ArrayList<Order>();
}

 

하이버네이트 @Fetch(FetchMode.SUBSELECT)

FetchMode를 SUBSELECT로 사용하면 연관된 데이터를 조회할 때 서브 쿼리를 사용해서 N+1 문제를 해결한다.

@Entity
public class Member {
	@Fetch(FetchMode.SUBSELECT)
    @OneToMany(mappedBy = "member", fetch = FetchType.EAGER)
    private List<Order> orders = new ArrayList<Order>();
}

즉시 로딩으로 설정하면 조회 시점에
지연 로딩으로 설정하면 사용하는 시점에 실행
SELECT O FROM ORDERS O
	WHERE O.MEMBER_ID IN (
    	SELECT
        	M.ID
        FROM
        	MEMBER M
        WHERE M.ID > 10
    )

'JVM > JPA' 카테고리의 다른 글

SQL 쿼리 힌트 사용  (0) 2023.07.04
읽기 전용 쿼리의 성능 최적화  (0) 2023.07.04
영속성 컨텍스트와 프록시  (0) 2023.07.03
JPA 예외 처리  (0) 2023.07.03
엔티티 그래프  (0) 2023.07.03