N + 1 문제
데이터베이스의 관계형 모델과 테이블 간의 관계를 다룰 때 주로 발생한다.
한 개의 쿼리로 데이터를 조회할 때, 해당 데이터에 연관된 다른 데이터들을 조회할 때
추가적인 쿼리가 n개 발생하는 현상이다.
주로 ORM(Object-Relational Mapping) 라이브러리를 사용하는 애플리케이션에서 발생하며,
지연 로딩(Lazy Loading)을 사용할 때 주로 발생한다.
해결 방법
해결방법으로는 Eager Loading(즉시 로딩)과 Fetch Joing이 있다.
1. Eager Loading(즉시 로딩)
JPA에서 연관된 엔티티를 LAZY로딩으로 설정하여 쿼리가 실행될 때
실제로 연관된 엔티티를 가져오지 않고, 필요할 때 가져오도록 설정이 되어있다.
Earger Loading을 사용하면 연관된 엔티티들을 즉시 한 번의 쿼리로 모두 가져올 수 있다.
@Entity
public class Post {
// ...
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "author_id")
private Author author;
// ...
}
하지만 Eager Loading은 대부분의 상황에서 권장되지 않는 방법이다.
- 성능 저하
✔ 연관된 엔티티를 모두 가져오기 때문에, 실제로 사용하지 않는 엔티티까지 불필요하게 가져올 수 있다. - 메모리 부하
✔ 연관된 엔티티들을 모두 로딩하기 때문에, 가져올 데이터의 양이 많으면 메모리의 부하가 커질 수 있다.
➜ 이는 성능 저하로 이어질 것이다. - 관계의 깊이
연관된 에티티들이 또 다른 연관 엔티티들과 계속해서 연결되어 있는 경우, 데이터를 가져오는데 필요한 쿼리의 수가 기하급수적으로 증가할 것이다. - JPA에서는 기본적으로 연관된 엔티티를 지연 로딩으로 설정하는 것을 권장한다.
➜ 필요한 시점에 데이터를 가져와서 불필요한 데이터를 가져오지 않을 수 있다.
2. Fetch Join
Fetch Join은 JPQL에서 사용할 수 있다.
JPQL에서 INNER JOIN FETCH를 사용하여 연관된 엔티티들을 한 번의 쿼리로 모두 가져온다.
public interface PostRepository extends JpaRepository<Post, Long> {
@Query("SELECT p from Post p left join fetch p.name")
List<Post> findPost();
}
Fetch Join도 남발할 경우 Eager Loading과 비슷한 문제가 발생할 수 있으니
상황에 맞게 Lazy Loading과 Fetch Join을 적절하게 사용하여야 한다.
'자바 탐구' 카테고리의 다른 글
자바) Stream API - 1) 람다 표현식(Lambda Expression) (0) | 2024.06.09 |
---|---|
스프링) 스프링이란? (0) | 2024.05.14 |
자바) 예외 클래스 (0) | 2023.08.01 |
자바) 오버로딩과 오버라이딩 (0) | 2023.07.31 |
스프링) @SpringBootTest와 @WebMvcTest의 차이 (0) | 2023.07.25 |