n+1 문제
요약
1:N, N:N 연관관계가 설정된 엔티티 조회할 경우 해당 엔티티와 관련된 컬렉션을 사용할때 n번의 추가 쿼리가 발생하는 문제, 이 때문에 데이터베이스에 대량의 쿼리가 실행되어 성능 문제가 발생할 수 있음
상세설명
N+1 문제는 데이터베이스 쿼리 성능과 관련된 문제 중 하나로, 주로 ORM(Object-Relational Mapping)을 사용하는 경우에 발생합니다. N+1 문제는 다음과 같은 상황에서 발생합니다.
- 하나의 쿼리로 엔티티를 가져올 때 (1번 쿼리)
- 이후 해당 엔티티와 관련된 컬렉션(OneToMany 또는 ManyToMany 등)을 사용할 때 (N번 추가 쿼리)
이때 총 실행되는 쿼리의 수는 N+1이 되므로 "N+1 문제"라고 부릅니다.
간단한 예를 통해 설명하겠습니다. 예를 들어, 블로그 포스트(Post) 엔티티와 그에 속한 댓글(Comment) 엔티티가 있다고 가정해봅시다.
- 첫 번째 쿼리로 블로그 포스트를 가져옵니다.
- 그 후에 각 블로그 포스트에 대해 관련된 댓글을 가져오는 쿼리가 실행됩니다.
1. List<Post> posts = entityManager.createQuery("SELECT p FROM Post p", Post.class).getResultList();
2. for (Post post : posts) {
List<Comment> comments = post.getComments(); // 각각의 블로그 포스트에 대해 N개의 추가 쿼리
}
이런 식으로 각각의 블로그 포스트마다 추가적인 쿼리가 발생하게 되는데, 이 때문에 데이터베이스에 대량의 쿼리가 실행되어 성능 문제가 발생할 수 있습니다.
해결방법
N+1 문제를 해결하기 위한 방법 중 하나는 Eager 로딩 대신 Lazy 로딩을 사용하는 것입니다.
Lazy 로딩은 실제로 데이터가 필요한 순간까지 데이터를 불러오지 않고, 그 시점에서 쿼리를 실행합니다.
이를 통해 N+1 문제를 피할 수 있습니다.
이것도 근본적인 해결은 아니기에
다른 방법으로는 Fetch Join 등의 방법을 사용하여 연관된 엔티티들을 한 번에 로딩할 수 있습니다.
Lazy Loading 사용:
- 대부분의 ORM 프레임워크는 지연 로딩(Lazy Loading)을 기본적으로 사용합니다. 이는 연관된 엔티티나 컬렉션을 실제로 필요한 시점까지 데이터베이스에서 불러오지 않고, 필요한 순간에 쿼리를 실행하는 방식입니다.
- 예를 들어, JPA에서는 @OneToMany 또는 @ManyToMany 관계에 대한 기본 설정이 Lazy Loading이며, 이를 통해 N+1 문제를 방지할 수 있습니다.
@Entity
public class Post {
// ...
@OneToMany(mappedBy = "post", fetch = FetchType.LAZY)
@BatchSize(size = 10) // 일정 개수의 묶음으로 로딩
private List<Comment> comments;
// ...
}
@Entity
public class Post {
// ...
@OneToMany(mappedBy = "post", fetch = FetchType.LAZY)
private List<Comment> comments;
// ...
}
Fetch Join 사용:
- Fetch Join은 한 번의 쿼리로 연관된 엔티티들을 함께 로딩하는 방법입니다. 이를 사용하면 N+1 문제를 효과적으로 해결할 수 있습니다.
- JPQL에서 FETCH JOIN을 사용하는 예제:
List<Post> posts = entityManager.createQuery(
"SELECT p FROM Post p LEFT JOIN FETCH p.comments", Post.class)
.getResultList();
Batch Size 설정:
- 일부 ORM 프레임워크에서는 Batch Size를 설정하여 한 번의 쿼리로 여러 엔티티를 로딩할 수 있습니다. 이는 일종의 페이징 기법으로, 연관된 엔티티를 일정 개수만큼 묶어서 한 번에 로딩하는 방법입니다.
//application.yml
spring:
jpa:
properties:
hibernate:
default_batch_fetch_size: 1000
추가 참고 링크
https://programmer93.tistory.com/83
'TIL' 카테고리의 다른 글
관계형 데이터베이스 (RDBMS)와 비관계형 데이터베이스 (0) | 2023.12.14 |
---|---|
Tags In HTML (0) | 2023.07.05 |
Spring MVC Testing JUnit Hamcrest (0) | 2023.05.24 |
Spring MVC Testing 단위 테스트 (0) | 2023.05.23 |
자료구조 Graph traversal (0) | 2023.05.17 |