DB

FETCH JOIN

KJihun 2025. 3. 18. 15:17
728x90

FETCH JOIN

ORM(Object-Relational Mapping) 프레임워크나 SQL에서 JOIN 된 엔티티를 한 번의 쿼리로 가져오는 기법

  • 일반적으로 SQL의 JOIN은 기본적으로 지연 로딩(Lazy Loading) 방식으로 동작한다
  • FETCH JOIN을 사용하면 즉시 로딩(Eager Loading) 방식으로 가져와 여러 번의 쿼리를 실행(N+1) 하는 것을 방지할 수 있다

2. FETCH JOIN in SQL (JPA / Hibernate)

📌 일반 JOIN (Lazy Loading)

SELECT e FROM Employee e JOIN e.department d;
  • 이 경우, 지연 로딩(Lazy Loading)으로 처리되며, department 데이터는 필요할 때 추가 쿼리가 발생한다

📌 FETCH JOIN (Eager Loading)

SELECT e FROM Employee e JOIN FETCH e.department;
  • department 데이터도 즉시 로딩되며, 한 번의 쿼리만 실행되므로 성능이 향상된다

 

FETCH JOIN의 장점

즉시 로딩 → 한 번의 쿼리로 연관된 데이터를 가져옴
N+1 문제 해결 → JPA에서 Lazy Loading을 사용할 때 발생하는 N+1 문제를 방지

 

FETCH JOIN 사용 시 주의할 점

  • 한 번에 많은 데이터를 가져오기 때문에, 데이터가 많아지면 메모리 사용량이 증가한다
  • DISTINCT를 사용하지 않으면 중복 데이터가 발생할 수 있다
  • 페이징 불가능 (JOIN FETCH + LIMIT 조합 불가)
    • JPA / Hibernate에서는 FETCH JOIN을 사용할 경우, 페이징 (LIMIT, OFFSET)이 제대로 동작하지 않음
    • 이유: FETCH JOIN이 실행되면, 모든 데이터를 먼저 가져온 후 메모리에서 페이징을 수행하기 때문

예제 (페이징 적용 실패)

TypedQuery<Employee> query = em.createQuery(
    "SELECT e FROM Employee e JOIN FETCH e.department", Employee.class
);
query.setFirstResult(0);
query.setMaxResults(10);  // ❌ 동작하지 않음!
  • 이 경우, 모든 데이터를 가져온 후 10개만 메모리에서 추려내므로, 쿼리 성능 저하
  • 해결 방법
    • JOIN FETCH를 제거
    • 서브쿼리 방식을 활용

서브쿼리 활용

SELECT e FROM Employee e 
WHERE e.id IN (
    SELECT e2.id FROM Employee e2 ORDER BY e2.id LIMIT 10
) 
JOIN FETCH e.department;
  • LIMIT으로 10개 데이터를 추려낸 후 JOIN FETCH를 수행
  • Hibernate에서는 기본적으로 지원하지 않으므로, 네이티브 쿼리를 활용하여야 함