orm을 사용하는 애플리케이션에서 자주 발생하는 성능 이슈 중 하나로
데이터베이스에서 엔티티를 검색할 때 해당 엔티티와 관계를 맺은 다른 엔티티들을 함께 가져오지 않고, 그 후에 각 엔티티에 대한 추가 쿼리를 실행하는 경우에 발생한다.
@DisplayName("게시물 별 댓글 수 출력")
@Test
void t() {
List<Article> articles = articleService.findAll();
articles.forEach(article -> {
System.out.println("게시물 번호 : " + article.getId());
System.out.println("댓글 수 : " + article.getComments().size());
});
}
위의 테스트 코드를 실행하면 게시물을 가져오기 위해 1 번의 쿼리가 발생하고
SELECT * FROM articles;
댓글을 가져오기 위해 N번의 추가 쿼리가 발생한다.
SELECT * FROM article_comment WHERE article_id = 1;
SELECT * FROM article_comment WHERE article_id = 2;
...
SELECT * FROM article_comment WHERE article_id = N;
때문에 N+1 문제가 발생한다.
Hibernate의 'default_batch_fetch_size' 속성을 사용하여 해결할 수 있다.
이 속성은 연관된 엔티티의 컬렉션을 가져올 때 일괄 쿼리를 사용하여 데이터를 가져오는 방식을 지정한다.
spring:
jpa:
properties:
hibernate:
default_batch_fetch_size: 20
위의 설정처럼 size를 20으로 설정하면 1번 게시글의 댓글을 조회할 때 20개의 게시글에 대한 댓글을 조회하여 성능을 향상시킬 수 있다.