N+1 문제와 FETCH

coldrice99·2024년 11월 14일
0
post-thumbnail

N+1 문제와 FETCH JOIN으로 해결하기


N+1 문제란?

N+1 문제는 데이터베이스 성능을 저하시키는 대표적인 문제입니다. 특히 연관된 엔티티를 조회할 때 발생하며, 한 번의 기본 쿼리(N) 이후, 연관 엔티티를 조회하기 위한 추가 쿼리(+1)가 반복적으로 발생합니다.

예시 상황

  • 예를 들어, Comment 엔티티 목록을 조회하면서 각 댓글 작성자의 정보를 가져와야 한다고 가정해 보겠습니다.
    • 1개의 기본 쿼리: 댓글 목록을 가져오는 쿼리가 실행됩니다.
    • N개의 추가 쿼리: 각 댓글의 작성자(User) 정보를 조회하기 위해 추가 쿼리가 발생합니다.

문제 코드와 쿼리 로그

문제 코드 (N+1 문제 발생)

단순히 JOIN만 사용하면 Comment와 연관된 User 데이터가 지연 로딩(Lazy Loading) 방식으로 개별 조회되면서 N+1 문제가 발생합니다.

@Query("SELECT c FROM Comment c JOIN c.user WHERE c.todo.id = :todoId")
List<Comment> findByTodoIdWithUser(@Param("todoId") Long todoId);

N+1 문제 발생 시의 Hibernate 쿼리 로그

예를 들어, 댓글이 3개 있을 때 다음과 같은 쿼리들이 실행됩니다:

-- 1. 첫 번째 쿼리: 댓글(Comment) 목록 조회
SELECT c1_0.id, c1_0.contents, c1_0.todo_id, c1_0.user_id 
FROM comments c1_0 
WHERE c1_0.todo_id = :todoId;

-- 2. 각 댓글의 작성자(User)를 개별 조회 (총 3회)
SELECT u1_0.id, u1_0.email, u1_0.nickname 
FROM users u1_0 
WHERE u1_0.id = ?;

SELECT u1_0.id, u1_0.email, u1_0.nickname 
FROM users u1_0 
WHERE u1_0.id = ?;

SELECT u1_0.id, u1_0.email, u1_0.nickname 
FROM users u1_0 
WHERE u1_0.id = ?;

이렇게 각 댓글마다 User를 조회하는 추가 쿼리가 발생하여 성능이 저하됩니다.


N+1 문제 해결: JOIN FETCH 사용하기

JOIN FETCH는 연관된 엔티티를 즉시 로딩하여 한 번의 쿼리로 모든 데이터를 조회합니다. 이를 통해 N+1 문제를 해결할 수 있습니다.

해결 코드: JOIN FETCH 사용

@Query("SELECT c FROM Comment c JOIN FETCH c.user WHERE c.todo.id = :todoId")
List<Comment> findByTodoIdWithUser(@Param("todoId") Long todoId);

N+1 문제 해결 후의 Hibernate 쿼리 로그

JOIN FETCH를 사용하여 댓글 3개를 조회할 때는 다음과 같이 단일 쿼리로 모든 데이터가 조회됩니다:

-- 단일 쿼리로 Comment와 User를 모두 조회 (N+1 문제 해결)
SELECT c1_0.id, c1_0.contents, c1_0.todo_id, c1_0.user_id, 
       u1_0.id, u1_0.email, u1_0.nickname 
FROM comments c1_0 
JOIN users u1_0 ON c1_0.user_id = u1_0.id 
WHERE c1_0.todo_id = :todoId;

JOIN FETCH를 통해 추가적인 쿼리 발생 없이 필요한 모든 데이터를 한 번에 가져오므로 성능이 크게 개선됩니다.


요약

  • N+1 문제: 연관된 엔티티를 지연 로딩할 때 개별적으로 추가 쿼리가 발생하는 문제.
  • JOIN FETCH를 사용한 해결: 단일 쿼리로 연관 데이터를 즉시 로딩하여 추가 쿼리 없이 필요한 데이터를 모두 조회.

JOIN FETCH를 사용하면 데이터베이스 부하를 줄이고, N+1 문제를 해결하여 성능을 최적화할 수 있습니다.

profile
서두르지 않으나 쉬지 않고

0개의 댓글