BackEnd/JPA

[JPA] 프록시(Proxy) - 즉시 로딩 & 지연 로딩

JJangGu 2022. 6. 3. 01:21

이번에는 즉시 로딩과 지연 로딩에 대해서 이야기해보겠습니다. JPA를 처음보면 모든게 낯선 개념이지만 이 지점부터는 점점 생각할게 많아지는 영역이라고 생각합니다. 최적화와 관련이 있고 N+1 문제 등 이슈와 관련이 있는 내용입니다. 물론 나중에 작성할 내용이지만 관련이 있다는 생각을 하고, 이 주제에 대해 공부를 시작하면 도움이 된다고 생각합니다.

 

즉시 로딩(Eager Loading)

엔티티를 조회할 때 연관된 엔티티도 함께 조회한다.

 

지연 로딩(Lazy Loading)

연관된 엔티티를 실제 사용할 때 조회한다.

 

간단한 특징이자 정의입니다. 이름 그래도 동작하기 때문에 사실 정의라고 할 것이 없습니다. 필요할때 조회해오느냐 아니면 먼저 조회해서 가지고 있느냐 의 차이입니다. 

 

먼저 즉시 로딩을 보겠습니다. 

 

@Entity
public class Member {
    // ...
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "TEAM_ID")
    private Team team;
    
    ...
}

 

이렇게 FetchType.EAGER 로 설정을 하면 Member 엔티티를 조회할 때 Team 엔티티도 같이 로딩한다는 설정입니다. 

 

이때 JPA 구현체는 즉시 로딩을 최적화하기 위해서 가능하면 조인을 이용해서 엔티티를 조회합니다.

 

그런데 여기서 하나 생각해볼 문제가 있습니다. 조인을 사용해서 조회를 하는데, 쿼리 실행 계획을 보신분이라면 Inner Join 을 사용하는 쪽이 Outer Join 보다 성능상의 이점이 있다는 것을 아실 겁니다. 

 

그렇다면, JPA 에서도 Outer Join 을 사용하는 것을 경계해야 합니다. 어떻게 하면 Inner Join을 사용하게 할 수 있을까요? 

Outer Join 을 사용할 때는 연관된 데이터에 null 이 있을 경우입니다. 물론 최적화를 하다보면 CTE 를 사용하거나, 어떤때는 union 을 사용하는게 최적화에 도움이 될 때가 있습니다. 하지만 흔히 Outer Join 이 필요할 때는 Join 하고자 하는 데이터와 매핑했을때 어느한쪽이 null 인 경우가 있을 때 입니다. 

 

그러면, JPA 에게도 이 엔티티를 조회할 때 Not NULL 임을 보장해준다면, Inner Join 을 사용하게 되는 것이죠. 

 

Outer Join 은 생각보다 성능을 많이 떨어뜨립니다. 이 점을 유의하시길 바랍니다. 

 

다음으로는 지연 로딩에 대해서 보겠습니다.

 

@Entity
public class Member {
    // ...
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "TEAM_ID")
    private Team team;
    
    ...
}

 

아까와는 다르게 FetchType.LAZY 라고 적어주었습니다. 이렇게 되면 지연 로딩을 사용한다고 설정한 것 입니다. 이 때는 회원 엔티티만 호출한 경우에 팀은 조회하지 않고, 프록시 객체를 넣어둡니다. 

 

프록시 객체는 앞서 살펴본대로 실제 사용될 때까지 데이터의 로딩을 미룹니다. 실제 데이터가 필요한 순간에 프록시 객체의 초기화기 이루어지면서 이를 지연 로딩이라고 합니다. 

 

즉시 로딩과 지연 로딩에 대한 개념은 사실 이게 끝입니다. 

 

좀 더 덧붙이자면, 실제로 개발을 할 때에는 지연 로딩을 사용하는 것이 좋습니다. 물론 항상 같이 조회해야 되는 엔티티는 즉시 로딩을 사용하겠지만, 그런 경우가 아니라면 지연 로딩을 사용하는 것이 좋습니다. 특히 컬렉션의 경우에 즉시 로딩을 사용하면 Outer Join 을 사용하게 됩니다. 이는 성능 최적화에도 영향을 미치므로 지연 로딩을 사용하면서 컨트롤 하는게 이점이 있습니다.

 

나중에 QueryDsl 같은 것을 다룰때, fetch 를 활용하면서 N + 1 에 대한 문제나 즉시 로딩에 대한 단점을 해결하기도 하는데 이것도 지연 로딩을 사용하면서 필요한 순간에 즉시로딩을 쓰면서 최적화를 하는 것을 권장하는 것으로 알고 있습니다. 

 

이런 것들을 생각하면서 지연 로딩을 활용하면 좋을 것 같습니다. 

 

이번 글은 여기서 마치고, 다음은 영속성 전이에 대해서 학습을 하겠습니다. 👍