@EntityGraph로 N+1 문제 해결하고 쿼리 수 줄이기
댓글 목록과 유저 정보를 함께 조회할 때 발생하는 N+1 문제를 @EntityGraph를 통해 어떻게 최적화했는지 정리한 글입니다
2025.06.16
문제 상황
이전 프로젝트 할 때만 해도, 로그는 에러가 떠야지만 살펴봤는데.. 뭔가 더 좋은 결과를 만들고 싶은 마음에 로그를 잘~ 확인하게 되었다.
댓글 조회할 때 총 4번의 쿼리가 작동함.
-
게시글 존재 확인
SELECT * FROM post WHERE id = ?;
-
댓글 목록 조회
SELECT * FROM comment WHERE post_id = ? AND is_deleted = false AND is_reported = false ORDER BY created_at LIMIT ?, ?;
-
유저 정보 조회
SELECT * FROM user WHERE id = ?;
-
댓글 전체 개수 조회(페이지 계산용)
SELECT COUNT(*) FROM comment WHERE post_id = ? AND is_deleted = false AND is_reported = false;
댓글 목록과 유저 정보 조회시 n+1 문제가 발생함.
- Comment → user 을 Lazy로 fetch 하게 되면, 댓글 n개 조회 후 각각 getUser 호출하므로 N개의 쿼리 추가 발생, 1(댓글 목록) + n(유저) 쿼리 실행
줄일 수 있는 부분은 댓글 목록 조회시 유저 정보를 join fetch 해서 같이 조회하는 것
@EntityGraph(attributePaths = {"user"})
Page<Comment> findByPostIdAndIsDeletedFalseAndIsReportedFalse(...);
결과 쿼리
from comment c1_0
left join post p1_0 on p1_0.id = c1_0.post_id
join `user` u1_0 on u1_0.id = c1_0.user_id
where p1_0.id = ?
and not(c1_0.is_deleted)
and not(c1_0.is_reported)
order by c1_0.created_at
- 댓글(Comment) 기준으로 작성자(User)까지 한번에 join
- 쿼리 수 1회로 최적화 완료!
- comment 테이블에서 댓글 목록 조회
- post는 left join으로 댓글에 연결된 게시글 정보 존재 여부 확인
- user은 join으로 확인
- 조건(where) 삭제 안된거, 신고 안된거
- 정렬 댓글 생성일 기준 오름차순
- 물론 게시글 존재확인, 댓글 총 개수 조회는 여전히 호출된다.
성능 테스트를 통해 수치를 확인하지는 못했지만, 쿼리 수를 줄이는 구조적 개선을 시도했다는 것으로.. 유의미한 경험이라 생각한다. 댓글 수가 많아지면 효과가 크게 나지 않을까..?