스프링 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
에 대한 글은 다음 포스트에서 확인해보자!..
'Spring > Spring Jpa' 카테고리의 다른 글
LazyInitializationException과 LazyLoading의 동작원리 (0) | 2025.02.19 |
---|---|
@ManyToMany를 사용하면 안 되는 이유 (0) | 2024.10.15 |
OSIV란? (feat.OSIV를 통한 성능 최적화) (0) | 2024.09.25 |
spring jpa를 활용한 데이터 저장 성능 향상(saveAll(), bulk insert) (1) | 2024.05.16 |