Spring @EntityGraph 왜 써야할까?

김현찬·2025년 6월 11일

@EntityGraph와 Fetch Join은 모두 N+1 문제를 해결하기 위해 사용하는 도구입니다.

@EntityGraph란?

  • JPA에서 연관된 엔티티를 즉시 로딩(Fetch Join) 하도록 선언하는 방법입니다.
    내부적으로 SQL문의 JOIN FETCH와 유사한 SQL을 자동 생성해줍니다.

  • JPQL 없이도 선언적으로 Fetch Join 사용이 가능합니다.

Fetch join 사용 방법

  • 쿼리문 안에 JOIN FETCH를 작성하여 사용합니다.
@Query("SELECT p FROM Post p JOIN FETCH p.author")
List<Post> findAllWithAuthor();

즉 위의 코드는 Post를 전체 조회 할 때 author필드도 함께 조회한다는 뜻을 지닙니다.

@EntityGraph 사용 방법

  • JPA Repository 인터페이스의 메서드에서 @EntityGraph(attributePaths = {연관필드명})으로 사용합니다.
  • fetch join 하고 싶은 연관 필드들의 경로를 지정해야 합니다.
@EntityGraph(attributePaths = {"user"})
List<Post> findAll();

즉 위의 코드는 Post를 전체 조회 할 때 user필드도 함께 조회한다는 뜻을 지닙니다.

@EntityGraph를 왜 써야할까?

그렇다면 두 기능 모두 N + 1문제를 해결하기 위해 사용하는 기능인데, @EntityGraph는 왜 사용해야 할까요?

저는 처음 @EntityGraph을 알게 되었을 때, 굳이 사용해야하나? 그냥 쿼리문 안에 JOIN FETCH쓰면 되는 거 아닌가? 하는 생각이 들었습니다.

그래서 어떤 상황에서 @EntityGraph를 사용하는지, 둘의 차이점에 대해 알아보았습니다.

@EntityGraph와 Fetch join의 차이

항목@EntityGraphFetch Join (JOIN FETCH)
사용 위치Spring Data JPA Repository 메서드JPQL 쿼리 (@Query 또는 EntityManager 사용 시)
문법 형태@EntityGraph(attributePaths = {"user"})SELECT p FROM Post p JOIN FETCH p.user
쿼리 작성 필요 여부❌ 쿼리 없이 선언적으로 지정✅ 직접 JPQL 쿼리 작성 필요
가독성 및 유지보수✅ 깔끔하고 선언적❌ 복잡한 쿼리 구조 가능성 있음
중첩 fetch 경로 지원"user.company"처럼 중첩 필드 fetch 가능✅ JOIN을 여러 번 명시해 중첩 fetch 가능
조건부 조인 가능 여부❌ 불가능 (조건 지정 불가)✅ WHERE, ON 조건 자유롭게 사용 가능
페이징(Pageable) 호환✅ 단일 관계(@ManyToOne 등)에서는 안전하게 사용 가능⚠️ 컬렉션 조인 시 페이징 깨짐
쿼리 재사용성✅ NamedEntityGraph로 재사용 가능❌ 반복 쿼리 직접 작성해야 함
N+1 문제 해결✅ 가능✅ 가능
JPA 표준 지원 여부✅ (jakarta.persistence.EntityGraph)✅ (JOIN FETCH는 JPQL 표준 문법)
대표 용도단순한 fetch join, 반복되는 fetch 로직 선언복잡한 조건 포함, 고도화된 쿼리 필요 시

작동 방식의 차이

항목@EntityGraphFetch Join (JOIN FETCH)
쿼리 생성 주체Spring Data JPA가 메서드 분석 후 내부적으로 JPQL + JOIN FETCH 생성개발자가 작성한 JPQL 그대로 사용됨
기본 조인 전략항상 LEFT JOIN FETCH (null 값 포함 가능성 고려)기본은 INNER JOIN FETCH, 명시적으로 LEFT 변경 가능
쿼리 실행 시점Repository 메서드 호출 시, 동적으로 쿼리 생성 및 실행JPQL이 컴파일 시점에 고정됨
JPQL에서 select 절 조작불가 – 항상 루트 엔티티 기준으로 select가능 – 필요한 필드만 SELECT new DTO(...)로 지정 가능
쿼리 결과 제어 가능성제한적 – fetch 대상만 제어 가능높음 – select, where, order by, join on 등 자유롭게 지정 가능
쿼리 해석의 유연성자동 처리 – 단순 fetch join 목적에 최적화수동 처리 – 복잡한 로직 및 성능 튜닝 시 유리
결과 중복 제거 처리기본적으로 필요 없음 (단일 연관일 때)컬렉션 fetch 시 중복 가능 → DISTINCT 필요
페치 대상 지정 방식attributePaths 문자열로 경로 지정JOIN FETCH로 명시적 경로 지정
join fetch 최적화 전략JPA 구현체가 내부적으로 최적화 적용 가능작성한 쿼리에 따라 성능이 크게 달라짐

둘의 차이점을 알아보니 어떤 상황에서 @EntityGraph를 사용하는지에 대한 판단이 비교적 쉬워졌습니다.

@EntityGraph를 사용해야 하는 대표적인 상황

번호사용해야 하는 상황설명
1JPQL 없이 간단하게 fetch join 하고 싶을 때쿼리 작성 없이 메서드 위에 @EntityGraph만 선언하면 자동으로 fetch join 처리 가능
2중첩된 연관 엔티티를 함께 로딩하고 싶을 때"user.company.department"처럼 깊은 연관 관계도 선언만으로 fetch 가능
3반복되는 fetch join을 재사용하고 싶을 때@NamedEntityGraph로 선언하면 여러 메서드에서 일관되게 재사용 가능
4쿼리 조건, DTO 매핑 없이 전체 엔티티 조회만 필요한 경우복잡한 select 조건 없이 루트 엔티티와 연관 필드만 간단히 조회할 때 적합

0개의 댓글