기본 지식
- N+1 문제 : 연관된 데이터를 조회할 때 불필요한 쿼리(select)가 다수 발생하는 성능 문제
- 즉시로딩 (eager loading)
- 엔터티를 조회할때 관련된 엔티티도 즉시 함께 로딩
- 사용하지 않는 연관 데이터도 전부 로딩
- Order 엔티티를 조회(findall)할 때 모든 OrderItem이 조회됨
- 개별적인 SELECT 쿼리가 반복적으로 실행
- 지연로딩 (Lazy loading):
- 연관데이터를 필요한 시점에 로딩
- Order 엔티티를 조회할 때 OrderItem은 로드되지 않음
- 개별적인 SELECT 쿼리가 반복적으로 실행
- Order를 조회할 때 OrderItem에 대한 데이터는 로드하지 않고, OrderItem 필드는 프록시 객체로 남아 있습니다. 연관 데이터(OrderItem)를 접근하려고 하면 그 시점에 데이터베이스에 쿼리를 날려 데이터를 가져옵니다.
- 프록시 객체는 실제 엔티티를 대신해서 사용하는 가짜 객체, 초기화 전에는 빈객체
- Batchsize (@BatchSize(size = 10))
- 지연 로딩 환경에서 다수의 데이터 쿼리를 최적화.
- SELECT IN (id1, id2, ...)로 한번의 쿼리로 다수의 연관 엔티티가져옴
- Fetch Join
- Fetch Join은 JPA의 JPQL에서 사용되는 특별한 JOIN 방식으로, 부모 엔터티와 자식 엔터티를 한 번에 로드합니다.
- SQL의 JOIN과 유사하지만, Fetch Join은 연관된 엔터티를 즉시 로드(EAGER Loading)하도록 강제
- select 다음에 엔티티 별칭 나와야댐
@Query("SELECT o FROM Order o JOIN FETCH o.orderItems WHERE o.status = :status") List<Order> findOrdersWithItemsByStatus(@Param("status") String status);
<aside> 💡
JPQL로 구현하기 복잡한 쿼리를 작성할때는 Native Query 사용 nativeQuery = true
- jpa 이점 상실, db 호환성 문제 발생
- @Query(value = "SELECT * FROM orders WHERE status = :status", nativeQuery = true) </aside>
🚨N+1 문제 발생 상황
- 즉시 로딩시 모든 관련 엔티티를 가져오는 select문 실행
- 지연로딩시 다수의 연관 엔티티를 활용시 N+1개의 가까운 select문 실행
🔍해결 방안
- Batchsize 사용 - sql select in
- fetch join 사용 - sql join
- Native Query 사용
사용 전략
- 즉시 로딩: 항상 연관 데이터를 사용하는 간단한 관계에서 사용.
- 지연 로딩: 조건부 로딩이 필요한 경우 기본 전략으로 사용하며, 최적화를 병행.
- BatchSize: 지연 로딩 환경에서 성능 최적화.
- Fetch Join: N+1 문제를 해결하거나 연관 데이터를 한 번에 가져와야 하는 경우.
- 실무에서는 지연 로딩(Lazy Loading)을 기본값으로 설정하고, 필요할 때 Fetch Join이나 BatchSize로 최적화하는 전략이 가장 많이 사용됩니다
'Spring' 카테고리의 다른 글
Spring MSA 멀티 모듈 레포 구성 방법 (0) | 2025.03.27 |
---|---|
[오류해결] Spring security CORS 문제 (0) | 2025.03.25 |
Spring Cloud Eureka MSA 사용법 (0) | 2025.03.06 |