N+1 Issue

N+1 문제

상황

Member Class

@Entity
@Table(name = "member")
public class Member {
    ...
    @Embedded
    private Favorites favorites;
    ...
}

Favorites Class

@Embeddable
public class Favorites {
    ...

    @OneToMany(mappedBy = "member", cascade = {CascadeType.PERSIST, CascadeType.MERGE}, orphanRemoval = true)
    private List<Favorite> favoriteCollection;

    ...
}

FavoriteData Class

StationData Class

FavoriteDataRepository Class

문제

테스트 결과

하위 Station 만큼 퀴리 N개 및 favoritedate 테이블 조회 퀴리 1개 총 N+1 개 발생한다.

해결 방법

방법1: JPQL

조인을 사용해서 조회시 station 까지 가져온다

테스트 결과

  • 하나의 쿼리 문제 해결

방법2: EntityGraph

EntityGraph의 attributePaths를 사용해서 한번 가져온다

테스트 결과

장단점

JPQL 방식

장점

  1. 유연성: JPQL을 사용하면 쿼리를 매우 세밀하게 제어할 수 있습니다. 복잡한 조인, 조건, 서브쿼리 등을 사용자 정의로 구현할 수 있습니다.

  2. 명시적인 쿼리: JPQL은 SQL과 유사하게 작성되므로 SQL에 익숙한 개발자에게는 쉽게 읽히고 이해됩니다.

단점

  1. 복잡성: 복잡한 쿼리를 작성하면 코드가 길어지고 이해하기 어려워질 수 있습니다.

  2. 오류 가능성: 쿼리에 오타나 로직 오류가 있을 경우, 오류를 찾기 어려울 수 있습니다

EntityGraph 방식

장점

  1. 간결함: EntityGraph를 사용하면 관련 엔티티를 명시적으로 지정하기만 하면 되므로 쿼리가 훨씬 간결해집니다.

  2. 오류 감소: 쿼리의 복잡성이 줄어들면서 잘못된 쿼리 작성에 따른 오류 가능성도 낮아집니다.

  3. 유지보수 용이: 쿼리의 간결함은 유지보수 시 이해하기 쉽고 수정하기 용이하게 만듭니다.

단점

  1. 유연성 제한: EntityGraph는 간결하지만, JPQL만큼 세밀한 쿼리 제어가 어렵습니다.

  2. 성능 이슈: 때때로 EntityGraph는 필요 이상의 데이터를 가져올 수 있으며, 이는 성능에 부정적인 영향을 미칠 수 있습니다.

결론

  • JPQL: 복잡하고 세밀한 쿼리가 필요할 때 유용하나, 복잡성과 오류 가능성을 고려해야 합니다.

  • EntityGraph: 간단하고 명확한 쿼리에 적합하며, 유지보수가 쉽지만, 유연성이 다소 제한됩니다.

나의 선택

쿼리의 세밀한 제어와 명식적인 쿼리를 더 좋아하고 복잡성은 감수하고 오류 가능성은 테스트로 충분히 해결 할수 있어서 JPQL를 선택했습니다.

기타

멤버 조회시 FetchType Lazy 전략 사용

Last updated