Spring/Spring Jpa

Eager Loading(즉시 로딩) vs Lazy Loading(지연 로딩) 중 어느 전략을 사용해야 할까?

윤밥밥 2024. 9. 24. 09:41

스프링 Jpa에서는 연관관계를 언제 DB에서 가져올 지 로딩 전략을 통해 결정할 수 있다.

이에 대해서는 즉시 로딩(Eager) or 지연 로딩(Lazy)가 존재한다.

 


지연 로딩(Lazy Loading)

지연 로딩 = 어떤 엔티티를 조회하였을 때 연관된 엔티티는 Proxy 객체( like 빈 객체)로 넣고, 실제로 사용될 때 DB 조회를 통해 가져온다.

지연 로딩은 N + 1 문제가 발생할 수 있다,

 

N + 1 문제란?

더보기

이는 1개의 쿼리로 N개의 데이터를 조회할 때, N개의 추가 쿼리가 발생하는 상황을 의미한다.

예를 들어 jpa를 통해 리스트(예를 들어 게시글)를 조회한다고 했을 때,

한 번의 쿼리(게시글 목록 조회)가 필요하다.

이 조회를 통해 N개의 리스트 원소를 가져왔다고 하자.

 가져온 각 게시글 안에 연관관계(게시글 주인 등)를 보려면 Lazy Loading의 경우 Proxy 객체로 필드를 채웠으므로,  DB 요청을 통해 정보를 가져와야 한다.

각 게시글마다 연관관계를 가져오는 쿼리를 날려 총 N번의 쿼리가 필요하다.

따라서 총 쿼리문을 N + 1 번 날리게 되므로 이를 N + 1문제라고 한다.

( 1 + N이라고 생각하는 게 더 편하다.)


즉시 로딩(Eager Loading)

즉시 로딩 = 어떤 엔티티를 조회하였을 때 연관된 엔티티도 모두 한번에 조회한다.

다만, 한번에 조회한다고 해서, 무조건 쿼리가 한 번이라는 것이 아니다.

즉 즉시 로딩 또한 경우에 따라 N + 1 문제가 발생할 수 있다.

 

즉시 로딩의 N + 1문제

더보기

즉시 로딩은 한 번에 가져오는 것이니까, 하나의 쿼리문으로 join을 활용해 연관관계까지 가져오지 않을까 생각할 수 다.

하지만 상황에 따라 즉시 로딩 또한 N + 1 문제가 발생한다.

 

@ManyToOne 연관관계인 경우=이 경우 특정 연관관계를 가져올 데이터가 하나이고, 한 번에 join하여 가져오는 게 좋다고 Jpa가 판단해 한 번에 가져온다.

@OneToMany 연관관계인 경우= 여러 리스트 객체를 한 번에 가져오는 것은 join 구조상 중복과 낭비를 야기할 수 있어, jpa는 한 번에 가져오지 않는다. 따라서 추가 쿼리로 연관관계 정보를 가져오기에 N + 1 문제가 발생한다.


그럼 즉시 로딩과 지연 로딩 중 어떤 것을 사용해야 할까?

개인적인 견해상, 즉시 로딩은 거의 사용하지 말아야 한다고 생각한다.

똑같이 N + 1 문제를 야기하기도 하며, 사용하지 않을 정보도 가져오기 때문이다.

따라서 기본적으로 지연 로딩을 사용하며, N + 1 문제를 지연로딩 안에서 해결하는 방법을 취한다.

이에 대한 해결책으로 fetch join 이 존재한다.

fetch join 에 대한 글은 다음 포스트에서 확인해보자!..