• JPA의 지연 로딩(Lazy Loading), 즉시 로딩(Eager Loading)

    2025. 3. 16.

    by. hyunji1109

    1. 지연 로딩(Lazy Loading)과 즉시 로딩(Eager Loading)

    JPA에서 @OneToMany, @ManyToOne, @OneToOne, @ManyToMany 같은 연관관계를 설정하면 연관된 엔티티를 언제 가져올지를 설정해야 한다. 이를 결정하는 것이 fetch 속성이다. 기본값은 연관관계에 따라 다르다.

     

    1.1 즉시 로딩(Eager Loading)

    즉시 로딩은 엔티티를 조회할 때 연관된 엔티티도 함께 가져오는 방식이다.

    @Entity
    public class Member {
        @Id @GeneratedValue
        private Long id;
        
        @ManyToOne(fetch = FetchType.EAGER) // 즉시 로딩
        private Team team;
    }

     

     

    즉시 로딩(FetchType.EAGER)을 설정하면 Member 엔티티를 조회할 때 Team도 즉시 같이 조회된다.

    SELECT * FROM member m JOIN team t ON m.team_id = t.id WHERE m.id = ?;

     

    📌 즉시 로딩의 단점

    • 필요하지 않은 연관 데이터를 함께 가져온다.
    • 쿼리가 복잡해질 가능성이 높다.
    • 성능 저하 가능성이 있다.
    즉시 로딩은 필요한 경우가 아니면 사용하지 않는 것이 좋다.

     

    1.2 지연 로딩(Lazy Loading)

    지연 로딩은 연관된 엔티티를 실제로 사용할 때 가져오는 방식이다.

    @Entity
    public class Member {
        @Id @GeneratedValue
        private Long id;
        
        @ManyToOne(fetch = FetchType.LAZY) // 지연 로딩
        private Team team;
    }

     

    이제 Member 엔티티를 조회해도 Team은 바로 가져오지 않고, 실제로 getTeam()을 호출할 때 쿼리가 실행된다.

    Member member = em.find(Member.class, 1L); // 여기서는 Team 조회 X
    Team team = member.getTeam(); // 여기서 Team 조회 쿼리 실행
    SELECT * FROM member WHERE id = ?;  -- member 조회
    SELECT * FROM team WHERE id = ?;    -- team 조회 (필요할 때 실행)

     

    📌  지연 로딩의 장점

    • 필요한 데이터만 조회하여 성능을 최적화할 수 있다.
    • 불필요한 쿼리 실행을 줄일 수 있다.
    연관된 엔티티를 많이 조회하는 경우에는 N+1 문제가 발생할 수 있다.

     

     

    2. N+1 문제

    Member 엔티티 리스트를 가져올 때 각 Member가 Team을 가지고 있다면 아래와 같이 쿼리가 실행될 수 있다.

    List<Member> members = em.createQuery("SELECT m FROM Member m", Member.class).getResultList();
    SELECT * FROM member;  -- 1개의 쿼리 실행 (N개의 Member 조회)
    SELECT * FROM team WHERE id = ?;  -- N개의 Member에 대해 N번 실행

    1개의 Member 리스트를 가져오는 쿼리 1번 +
    각 Member의 Team을 가져오는 N번의 추가 쿼리 → 총 N+1개의 쿼리 실행

     

    📌 N+1 문제의 해결 방법

    • Fetch Join 사용
    • Entity Graph 사용
    • Batch Size 설정
     N+1 문제 어떻게 해결해야할까

     

    3. N+1 문제 해결 방법

    3.1 Fetch Join 사용

    JOIN FETCH를 사용하면 한 번의 쿼리로 필요한 데이터를 모두 조회할 수 있다.

    List<Member> members = em.createQuery(
        "SELECT m FROM Member m JOIN FETCH m.team", Member.class
    ).getResultList();
    SELECT * FROM member m JOIN team t ON m.team_id = t.id;

    Fetch Join의 장점

    • N+1 문제를 해결할 수 있다.
    • 쿼리 실행 횟수를 최소화하여 성능을 개선할 수 있다.

     

    3.2 Entity Graph 사용

    JPA의 @EntityGraph를 활용하면 지연 로딩을 유지하면서 특정 상황에서만 즉시 로딩을 적용할 수 있다.

    @EntityGraph(attributePaths = {"team"})
    @Query("SELECT m FROM Member m")
    List<Member> findAllWithTeam();

     

     

     

    'CS > 웹개발' 카테고리의 다른 글

    Handlebars.js vs Thymeleaf  (0) 2025.03.19
    React  (0) 2025.03.18
    데이터 빠르게 찾기 - 인덱스 설정하기  (0) 2025.03.12
    TDD  (0) 2025.01.23
    Docker  (0) 2025.01.20

    댓글