컴퓨터 프로그래밍/Spring

[Spring] Lazy Loading 과 Eager Loading 의 차이, N+1 Problem 과 해결 방법

한33 2024. 10. 3. 16:45

1. Lazy Loading (지연 로딩)

  • 특징: 연관된 엔티티를 필요할 때 로드함. 처음에는 관련 데이터가 로드되지 않고, 실제로 데이터를 사용할 때 쿼리가 실행됨.
  • 장점: 불필요한 데이터를 미리 로드하지 않으므로 성능에 유리함. 데이터 접근이 적을 때 효과적이다.
  • 단점: 연관 데이터에 접근할 때마다 쿼리가 발생해 N+1 문제가 발생할 수 있다.

2. Eager Loading (즉시 로딩)

  • 특징: 연관된 엔티티를 즉시 로드함. 엔티티가 조회될 때 모든 연관된 데이터도 한 번에 가져온다.
  • 장점: 한 번에 모든 데이터를 로드하여 추가 쿼리가 발생하지 않는다. 필요할 때 미리 로드된 데이터를 사용할 수 있다.
  • 단점: 불필요한 데이터를 미리 로드하기 때문에 성능이 저하될 수 있다. 데이터가 많을 때는 비효율적이다.

N+1 Problem

  • 연관 관계가 설정된 엔티티 조회시, 관계 데이터 갯수(n) 만큼 조회 쿼리가 추가로 발생하여 데이터를 읽어오는 현상

  • 한쪽 테이블만 먼저 조회하고 연관 관계가 있는 다른 테이블은 따로 조회하기 때문
  • 관계가 많아지고 데이터가 커지면 N+1의 N이 데이터베이스 및 애플리케이션 전체 성능에 영향을 끼칠 수 있음

해결방법

Fetch Join

  • Fetch Join은 실제 SQL에 있는 Join의 종류가 아니며, JPQL에서 성능 최적화를 위해 제공하는 Join 기능
  • 연관된 엔티티나 컬렉션을 한 번에 같이 조회할 수 있도록 지원함
  • JPQL에서 JOIN FETCH 로 사용
@Query("SELECT t FROM Todo t JOIN FETCH t.managers")
List<Todo> findAll();
  • MultipleBagFetchException
    • ToMany를 여러개 Fetch Join 할 경우 발생
    • To One은 몇개든 Fetch Join 가능
    • ToMany는 1개만 Fetch Join 가능

 

Batch Size

  • 지정된 수만큼 in절에 부모 Key를 사용하게 해줌으로써, 1개씩 사용되는 조건문을 in절로 묶어서 조회하는 방법
    • MultipleBagFetchException의 해결 방법
  • 다중 관계에서 fetch join 및 batch size 설정 대상 정하는 기준
    • 호출량 차이가 있다면? → 호출량이 잦은 대상에 fetch로 한번에 가져오기
    • 호출이 가변적이라면? → 호출이 적은 대상에 batch size로 필요할때 적절한 크기 만큼 가져오기
    • 데이터양 차이가 난다면? → 데이터가 적은 대상은 fetch로 한번에 가져오고, 많은 대상은 batch size로 적절한 크기 만큼 가져오기
    • 결국 도메인의 특성, 비즈니스 로직 구성에 따라 적절히 판단 할 것!
@Query("SELECT DISTINCT t FROM Todo t JOIN FETCH t.managers JOIN t.comments")
    List<Todo> findAllJpqlFetch();
public class Todo {
    ...
    @OneToMany(mappedBy = "todo")
    @BatchSize(size = 10)
    private List<Comment> comments = new ArrayList<>();
    ...
}

 

'컴퓨터 프로그래밍 > Spring' 카테고리의 다른 글

[Spring] Spring Security  (0) 2024.10.04
[Spring] QueryDSL  (1) 2024.10.03
[Spring] Password Encoder 사용법  (0) 2024.09.29
[Spring] OAuth2.0 Kakao 소셜 로그인 기능 구현  (0) 2024.09.29
[Spring] S3 기능 구현  (1) 2024.09.28