본문 바로가기
Spring

[오류해결] jpa N+1 문제

by HanYaung 2025. 3. 26.

 

기본 지식

  • 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 문제 발생 상황

  1. 즉시 로딩시 모든 관련 엔티티를 가져오는 select문 실행
  2. 지연로딩시 다수의 연관 엔티티를 활용시 N+1개의 가까운 select문 실행 

 

🔍해결 방안

  1. Batchsize 사용 - sql select in
  2. fetch join 사용 - sql join
  3. 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