[JPA] 일반 JOIN과 FETCH JOIN을 지연 로딩(LAZY)과 즉시 로딩(EAGER)과 접목한 차이와 장단점
Java Persistence API(JPA)를 사용하면서 JOIN을 활용하여 여러 엔티티 간의 연관된 데이터를 조회하는 경우가 많다. 이 글에서는 JPA에서 일반 JOIN과 FETCH JOIN을 지연 로딩(LAZY)과 즉시 로딩(EAGER)과 접목했을 때의 차이와 각자의 장단점을 예시와 함께 살펴보겠다.
1. 일반 JOIN + 지연 로딩(LAZY)
일반 JOIN은 두 개 이상의 테이블을 조인하여 데이터를 조회하는 방법이다. 지연 로딩(LAZY)은 연관된 엔티티를 실제로 사용할 때까지 로딩하지 않는 방법이다.
public List<Order> findOrdersWithCustomerLazy() {
String jpql = "SELECT o FROM Order o JOIN o.customer c ON o.customer_id = c.id";
return entityManager.createQuery(jpql, Order.class).getResultList();
}
장점:
- 성능 최적화: 필요할 때만 데이터를 로딩하여 성능을 최적화할 수 있다.
- 메모리 절약: 사용되지 않는 데이터를 로딩하지 않기 때문에 메모리 사용을 절약할 수 있다.
단점:
- N + 1 문제: 일반 JOIN을 사용할 때 연관된 엔티티를 개별적으로 조회하기 때문에 다수의 쿼리가 발생할 수 있다.
- 초기화 문제: 연관된 엔티티를 접근할 때 LazyInitializationException이 발생할 수 있다.
2. 일반 JOIN + 즉시 로딩(EAGER)
일반 JOIN은 두 개 이상의 테이블을 조인하여 데이터를 조회하는 방법이다. 즉시 로딩(EAGER)은 엔티티를 조회할 때 연관된 엔티티도 함께 로딩하는 방법이다.
예시:
public List<Order> findOrdersWithCustomerEager() {
String jpql = "SELECT o FROM Order o JOIN o.customer c ON o.customer_id = c.id";
return entityManager.createQuery(jpql, Order.class).getResultList();
}
장점:
- 즉시 사용 가능: 조회 시점에 모든 데이터가 로딩되므로 바로 사용할 수 있다.
- 간단함: 단일 쿼리로 연관된 데이터를 모두 조회할 수 있다.
단점:
- 성능 저하: 불필요한 데이터를 모두 로딩하기 때문에 성능이 저하될 수 있다.
- 메모리 사용: 모든 데이터를 로딩하므로 메모리 사용량이 늘어날 수 있다.
3. FETCH JOIN + 지연 로딩(LAZY)
FETCH JOIN은 조인과 동시에 연관된 엔티티를 한 번에 로딩하는 방법이다. 지연 로딩(LAZY)은 연관된 엔티티를 실제로 사용할 때까지 로딩하지 않는 방법이다.
예시:
public List<Order> findOrdersWithCustomerFetchLazy() {
String jpql = "SELECT o FROM Order o JOIN FETCH o.customer c ON o.customer_id = c.id";
return entityManager.createQuery(jpql, Order.class).getResultList();
}
장점:
- 성능 최적화: 연관된 엔티티를 한 번에 로딩하여 N + 1 문제를 해결하고, 필요할 때만 데이터를 로딩하여 성능을 최적화할 수 있다.
- 메모리 절약: 사용되지 않는 데이터를 로딩하지 않기 때문에 메모리 사용을 절약할 수 있다.
단점:
- 복잡성: 쿼리 작성이 복잡할 수 있으며, 주의가 필요하다.
- 초기화 문제: 연관된 엔티티를 접근할 때 LazyInitializationException이 발생할 수 있다.
4. FETCH JOIN + 즉시 로딩(EAGER)
FETCH JOIN은 조인과 동시에 연관된 엔티티를 한 번에 로딩하는 방법이다. 즉시 로딩(EAGER)은 엔티티를 조회할 때 연관된 엔티티도 함께 로딩하는 방법이다.
예시:
public List<Order> findOrdersWithCustomerFetchEager() {
String jpql = "SELECT o FROM Order o JOIN FETCH o.customer c ON o.customer_id = c.id";
return entityManager.createQuery(jpql, Order.class).getResultList();
}
장점:
- 성능 향상: 연관된 엔티티를 한 번에 로딩하여 N + 1 문제를 해결한다.
- 즉시 사용 가능: 조회 시점에 모든 데이터가 로딩되므로 바로 사용할 수 있다.
단점:
- 성능 저하: 불필요한 데이터를 모두 로딩하기 때문에 성능이 저하될 수 있다.
- 메모리 사용: 모든 데이터를 로딩하므로 메모리 사용량이 늘어날 수 있다.
5. 결론
JPA에서 일반 JOIN과 FETCH JOIN을 지연 로딩(LAZY)과 즉시 로딩(EAGER)과 접목했을 때는 각각의 장단점이 있다. 일반 JOIN과 FETCH JOIN은 각각의 상황에 따라 적절히 선택하여 사용할 수 있으며, 지연 로딩(LAZY)과 즉시 로딩(EAGER)을 통해 성능과 메모리 사용을 조절할 수 있다. 상황에 맞게 적절한 방법을 선택하여 효과적으로 JPA를 활용 할 수 있다
'낙서장[1] > 3. JPA' 카테고리의 다른 글
[JPA] Spring Data JPA의 Pageable 인터페이스: 페이징과 정렬을 손쉽게 처리하기 (0) | 2025.01.24 |
---|---|
[JPA] JPQL 쿼리 설명 (0) | 2025.01.24 |
[JPA] 데이터베이스와 상호작용하는 객체 지향 프로그래밍 JPA 기초 (2) | 2025.01.24 |