Springintermediate검토 2026.08

Fetch Join

JPQL에서 연관 Entity를 한 SQL로 함께 조회해 지연 로딩의 추가 Query를 제어한다.

#JPA#JPQL#fetch-join#N+1

Overview

Fetch Join은 JPQL에서 조회 대상 Entity와 필요한 연관 Entity를 같은 SQL로 가져오는 기능이다. Entity Mapping의 기본 Fetch 전략을 바꾸지 않고 특정 Use Case의 조회 모양을 지정한다.

왜 필요한가

지연 로딩된 연관관계를 반복문에서 접근하면 최초 Entity Query 다음에 연관 Entity Query가 반복되는 N+1 문제가 생길 수 있다. Fetch Join은 필요한 관계가 명확한 조회에서 왕복 횟수를 줄인다.

핵심 원리

select m from Member m join fetch m.team

JPA는 Member와 Team 열이 결합된 SQL 결과를 읽고 Persistence Context의 식별자 기준으로 Entity를 구성한다. To-one 관계는 결과 행 수가 크게 늘지 않지만, To-many Collection을 Fetch Join하면 부모 한 건이 자식 수만큼 반복된다.

flowchart LR; A[JPQL join fetch] --> B[단일 SQL]; B --> C[반복된 Result Row]; C --> D[Persistence Context]; D --> E[Entity Graph 구성]

Example

List<Member> members = entityManager.createQuery(
    "select m from Member m join fetch m.team",
    Member.class
).getResultList();

select distinct t from Team t join fetch t.members는 부모 Entity 중복을 줄이는 의도를 표현한다. 다만 SQL 결과의 행 수와 전송량까지 사라진다고 이해하면 안 된다.

Collection Fetch Join과 Pagination

Collection Fetch Join은 한 부모가 여러 Row로 증폭되므로 DB 수준 Pagination과 충돌한다. Page 조회에서는 To-one을 Fetch Join하고 Collection은 Batch Fetch Size, 별도 Query, DTO Projection 등을 비교한다.

실무에서 발생하는 문제

  • 둘 이상의 Bag Collection을 동시에 Fetch Join하면 Hibernate 제약을 만날 수 있다.
  • Collection Fetch Join과 Pagination을 같이 사용하면 Memory에서 잘라내거나 경고가 발생할 수 있다.
  • 필요하지 않은 연관관계까지 한 번에 가져오면 Row 폭과 Network 비용이 증가한다.
  • distinct를 붙였다는 이유로 실행계획과 데이터 전송 비용을 확인하지 않는 실수가 생긴다.

Trade-off

Query 횟수는 줄지만 Join 결과 크기가 커질 수 있다. “한 번의 SQL”보다 총 Row 수, Column 폭, 사용 목적, Pagination 여부를 함께 판단한다.

Interview Questions

  1. 일반 Join과 Fetch Join은 JPA에서 어떤 차이가 있는가?
  2. Collection Fetch Join에서 결과 Row가 증가하는 이유는 무엇인가?
  3. Collection Fetch Join과 Pagination을 함께 사용하기 어려운 이유는 무엇인가?
  4. N+1을 해결할 때 Fetch Join 외에 어떤 선택지가 있는가?

Lazy Loading과 N+1에서 문제 발생 조건을, Persistence Context에서 Entity 동일성 구성을 함께 확인한다.

SOURCE REFERENCES

이 문서의 근거

본문은 Dev Atlas 안에서 완결되며, 검증이 필요할 때만 원문을 확인할 수 있습니다.

원문 출처 보기 3