@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) 삭제 안된거, 신고 안된거
    • 정렬 댓글 생성일 기준 오름차순
  • 물론 게시글 존재확인, 댓글 총 개수 조회는 여전히 호출된다.

성능 테스트를 통해 수치를 확인하지는 못했지만, 쿼리 수를 줄이는 구조적 개선을 시도했다는 것으로.. 유의미한 경험이라 생각한다. 댓글 수가 많아지면 효과가 크게 나지 않을까..?

Copyright © 2025 NahyunKim

Mag.dev