Lazy Loading, Eager Loading

김상진 ·2024년 12월 8일
0

CS

목록 보기
15/30

Lazy Loading, Eager Loading

JPA를 사용할 때 연관관계를 설정하면 데이터를 조회하는 방법에 따라 두 가지 방식으로 로딩됩니다:
1. Lazy Loading (지연 로딩)
2. Eager Loading (즉시 로딩)

이 글에서는 각 로딩 방식의 특징, 실제 쿼리문이 언제 실행되는지를 예제 코드와 함께 설명하겠습니다.


1. Lazy Loading (지연 로딩)

Lazy Loading은 연관된 엔티티 데이터를 즉시 가져오지 않고, 실제 사용할 때 조회하는 전략입니다.
JPA에서는 기본적으로 @OneToMany, @ManyToOne 관계를 설정할 때 FetchType.LAZY를 사용합니다.

특징

  1. 처음에 연관된 엔티티는 프록시 객체로 대체됩니다.
  2. 실제로 데이터를 접근(사용)하는 시점에 쿼리가 실행됩니다.
  3. 필요할 때만 데이터를 조회하기 때문에 성능 최적화에 유리합니다.

Lazy Loading 예제 코드

1. 엔티티 설정

@Entity
public class Parent {
    @Id @GeneratedValue
    private Long id;

    private String name;

    @OneToMany(mappedBy = "parent", fetch = FetchType.LAZY)
    private List<Child> children = new ArrayList<>();
}

@Entity
public class Child {
    @Id @GeneratedValue
    private Long id;

    private String name;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "parent_id")
    private Parent parent;
}

2. Lazy Loading 동작 확인

@Transactional
public void lazyLoadingExample(Long parentId) {
    // 부모 엔티티 조회
    Parent parent = parentRepository.findById(parentId).orElseThrow();

    // 여기서 쿼리는 아직 실행되지 않음 (children은 프록시 상태)
    System.out.println("Parent name: " + parent.getName());

    // 자식 엔티티에 접근하는 시점에서 쿼리 실행
    System.out.println("Number of children: " + parent.getChildren().size());
}

쿼리 실행 흐름

  1. parentRepository.findById() → 부모 엔티티만 SELECT 쿼리 실행

    SELECT * FROM parent WHERE id = ?;
  2. parent.getChildren().size() → 자식 엔티티 조회 시점에 쿼리 실행

    SELECT * FROM child WHERE parent_id = ?;

Lazy Loading의 장점과 단점

장점

  • 데이터를 필요할 때만 로딩하므로 성능 최적화가 가능합니다.
  • 불필요한 데이터를 미리 로딩하지 않습니다.

단점

  • 트랜잭션 범위 밖에서 Lazy 로딩된 객체에 접근하면 LazyInitializationException이 발생합니다.
  • 연관된 데이터를 사용할 때마다 추가 쿼리가 실행되므로 N+1 문제가 발생할 수 있습니다.

2. Eager Loading (즉시 로딩)

Eager Loading은 연관된 데이터를 즉시 조회하는 전략입니다.
JPA에서는 FetchType.EAGER로 설정하면 엔티티를 조회할 때 JOIN 쿼리를 통해 연관된 데이터도 함께 가져옵니다.

특징

  1. 조회 시점에 연관된 데이터를 한 번에 가져옵니다.
  2. 필요한 데이터뿐만 아니라 모든 연관 데이터가 함께 로딩되므로 성능 저하를 일으킬 수 있습니다.
  3. 코드 작성은 간단하지만 불필요한 데이터가 로딩될 가능성이 큽니다.

Eager Loading 예제 코드

1. 엔티티 설정

@Entity
public class Parent {
    @Id @GeneratedValue
    private Long id;

    private String name;

    @OneToMany(mappedBy = "parent", fetch = FetchType.EAGER)
    private List<Child> children = new ArrayList<>();
}

@Entity
public class Child {
    @Id @GeneratedValue
    private Long id;

    private String name;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "parent_id")
    private Parent parent;
}

2. Eager Loading 동작 확인

@Transactional
public void eagerLoadingExample(Long parentId) {
    // 부모 엔티티 조회
    Parent parent = parentRepository.findById(parentId).orElseThrow();

    // EAGER 로딩이므로 children도 함께 가져옴
    System.out.println("Parent name: " + parent.getName());
    System.out.println("Number of children: " + parent.getChildren().size());
}

쿼리 실행 흐름

  1. 부모 엔티티 조회 시 JOIN을 통해 자식 엔티티도 함께 가져옵니다.
    SELECT p.*, c.* 
    FROM parent p 
    LEFT JOIN child c ON p.id = c.parent_id 
    WHERE p.id = ?;

Eager Loading의 장점과 단점

장점

  • 쿼리가 한 번만 실행되므로 N+1 문제를 방지할 수 있습니다.
  • 코드 작성이 간단합니다.

단점

  • 불필요한 데이터까지 모두 조회하므로 성능 저하가 발생할 수 있습니다.
  • 데이터의 양이 많아질수록 오버헤드가 커집니다.

3. Lazy Loading과 Eager Loading 비교

구분Lazy LoadingEager Loading
데이터 로딩 시점실제로 필요할 때 조회엔티티 조회 시점에 즉시 조회
쿼리 실행연관 데이터 접근 시 개별 쿼리 실행JOIN 쿼리를 통해 한 번에 로딩
성능필요할 때만 로딩 → 성능 최적화 가능불필요한 데이터까지 로딩 → 성능 저하 가능
N+1 문제발생할 수 있음 (개별 쿼리 실행)발생하지 않음 (JOIN 사용)
활용 사례데이터 사용 빈도가 낮고 효율적 로딩이 필요할 때데이터 사용 빈도가 높고 JOIN이 유리할 때

4. 언제 Lazy와 Eager를 사용할까?

  • Lazy Loading

    • 연관된 데이터가 자주 사용되지 않는 경우
    • 성능 최적화가 필요한 경우
    • 데이터 양이 많을 때
  • Eager Loading

    • 연관된 데이터를 함께 사용해야 하는 경우
    • JOIN 쿼리를 사용해 한 번에 로딩하는 것이 성능상 유리할 때

마무리

Lazy Loading과 Eager Loading은 각기 다른 장단점을 가지고 있습니다.

  • Lazy Loading은 지연된 시점에 데이터를 가져오므로 불필요한 데이터 로딩을 피할 수 있지만 N+1 문제가 발생할 수 있습니다.
  • Eager Loading은 즉시 데이터를 가져오기 때문에 N+1 문제는 피하지만 불필요한 데이터까지 로딩될 수 있습니다.

따라서 상황에 맞는 로딩 전략을 선택하고, 필요하다면 JPQL의 Fetch Join을 사용해 쿼리 최적화를 진행하는 것이 좋습니다.


출처 및 참고 자료

  1. Spring Data JPA 공식 문서
  2. Hibernate User Guide - Fetching Strategies
  3. Baeldung: JPA Lazy vs Eager Loading
profile
알고리즘은 백준 허브를 통해 github에 꾸준히 올리고 있습니다.🙂

0개의 댓글

관련 채용 정보