Skip to content

refactor: N+1 problem 해결(query 수정)#177

Merged
c5ln merged 2 commits intodevelopfrom
refactor/175-n1-query
Feb 4, 2026
Merged

refactor: N+1 problem 해결(query 수정)#177
c5ln merged 2 commits intodevelopfrom
refactor/175-n1-query

Conversation

@c5ln
Copy link
Member

@c5ln c5ln commented Feb 4, 2026

팔로잉, 팔로워 조회 쿼리의 N + 1 문제 해결.

새로 작성한 코드는 다음과 같다.

  @Query("SELECT f FROM Follow f " +
         "JOIN FETCH f.follower u " +
         "LEFT JOIN FETCH u.avatarList " +
         "WHERE f.following = :following")
  List<Follow> findByFollowingWithFollowerAndAvatars(@Param("following") User following);



 @Query("SELECT f FROM Follow f " +
         "JOIN FETCH f.following u " +
         "LEFT JOIN FETCH u.avatarList " +
         "WHERE f.follower = :follower")
  List<Follow> findByFollowerWithFollowingAndAvatars(@Param("follower") User follower);

Summary by CodeRabbit

릴리스 노트

  • 리팩토링

    • 팔로워/팔로우 목록 조회 기능 최적화
  • 테스트

    • 팔로우 서비스 테스트 스위트 확대 및 강화

@c5ln c5ln self-assigned this Feb 4, 2026
@c5ln c5ln linked an issue Feb 4, 2026 that may be closed by this pull request
@coderabbitai
Copy link

coderabbitai bot commented Feb 4, 2026

요약

FollowRepository에 fetch join을 활용한 두 개의 새로운 쿼리 메서드를 추가하여 팔로워/팔로잉 목록 조회 시 관련 엔티티(아바타 포함)를 즉시 로딩하도록 최적화했으며, FollowService에서 이 새로운 메서드들을 사용하도록 업데이트하고, 아바타 시나리오를 포함한 포괄적인 테스트 스위트를 작성했습니다.

변경 사항

Cohort / File(s) 요약
Repository 최적화
src/main/java/com/example/cp_main_be/domain/social/follow/domain/repository/FollowRepository.java
Fetch join을 활용한 두 개의 새로운 JPQL 쿼리 메서드 추가: findByFollowerWithFollowingAndAvatars(팔로잉 목록 즉시 로딩), findByFollowingWithFollowerAndAvatars(팔로워 목록 즉시 로딩)
Service 메서드 업데이트
src/main/java/com/example/cp_main_be/domain/social/follow/service/FollowService.java
getFollowersgetFollowing 메서드에서 기존 repository 호출을 새로운 fetch join 메서드로 교체하여 N+1 쿼리 문제 해결
테스트 전체 재작성
src/test/java/com/example/cp_main_be/domain/social/follow/service/FollowServiceTest.java
주석 처리된 스켈레톤 테스트를 완전한 JUnit 5 + Mockito 기반 테스트 스위트로 교체, 아바타 시나리오 및 에러 핸들링 포함

예상 코드 리뷰 소요 시간

🎯 3 (보통) | ⏱️ ~20분

관련 PR

제안 라벨

Refactor

제안 리뷰어

  • xoruddl
  • lejuho

🐰 쿼리를 최적화하는 마법의 손길,
Fetch join으로 N+1을 해결하고,
아바타까지 함께 불러와,
테스트는 촘촘하게 감싸며,
팔로우 시스템이 더욱 빛나네! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목은 PR의 주요 변경사항인 N+1 쿼리 문제 해결을 명확하게 요약하고 있으며, 저장소 변경사항과 일치한다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/175-n1-query

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In
`@src/main/java/com/example/cp_main_be/domain/social/follow/domain/repository/FollowRepository.java`:
- Around line 16-28: Spotless formatting violations were detected in the
FollowRepository interface; run the formatter and commit the fixes by executing
./gradlew spotlessApply, then review and stage the changed files (notably the
FollowRepository methods findByFollowerWithFollowingAndAvatars, findByFollowing,
and findByFollowingWithFollowerAndAvatars) to ensure the query strings and
annotations conform to the project's Spotless rules before pushing the updated
commit.

In
`@src/main/java/com/example/cp_main_be/domain/social/follow/presentation/FollowController.java`:
- Line 48: There is an unnecessary blank line causing Spotless formatting
failure in FollowController; run the formatter to fix it by executing ./gradlew
spotlessApply and then commit the changes, or manually remove the extra empty
line(s) in the FollowController class (Search for class FollowController or
method definitions in FollowController to locate the offending blank line) so
the file matches the project's Spotless rules.

In
`@src/test/java/com/example/cp_main_be/domain/social/follow/service/FollowServiceTest.java`:
- Line 25: Remove the unused import org.junit.jupiter.api.BeforeEach from the
FollowServiceTest class (FollowServiceTest) to satisfy the linter; either run
./gradlew spotlessApply to auto-fix or manually delete the import line for
BeforeEach so no unused JUnit import remains.
🧹 Nitpick comments (3)
src/main/java/com/example/cp_main_be/domain/social/follow/domain/repository/FollowRepository.java (2)

16-20: 컬렉션 fetch join 사용 시 중복 결과 가능성 검토 필요

avatarList가 컬렉션인 경우, LEFT JOIN FETCH로 인해 카테시안 곱이 발생하여 Follow 엔티티가 중복될 수 있습니다. DISTINCT 키워드 추가를 권장합니다.

♻️ 중복 방지를 위한 DISTINCT 추가
-  `@Query`("SELECT f FROM Follow f " +
+  `@Query`("SELECT DISTINCT f FROM Follow f " +
          "JOIN FETCH f.following u " +
          "LEFT JOIN FETCH u.avatarList " +
          "WHERE f.follower = :follower")
   List<Follow> findByFollowerWithFollowingAndAvatars(`@Param`("follower") User follower);

24-28: 동일하게 DISTINCT 추가 권장

위와 동일한 이유로 중복 결과 방지를 위해 DISTINCT 추가를 권장합니다.

♻️ 제안
-  `@Query`("SELECT f FROM Follow f " +
+  `@Query`("SELECT DISTINCT f FROM Follow f " +
          "JOIN FETCH f.follower u " +
          "LEFT JOIN FETCH u.avatarList " +
          "WHERE f.following = :following")
   List<Follow> findByFollowingWithFollowerAndAvatars(`@Param`("following") User following);
src/test/java/com/example/cp_main_be/domain/social/follow/service/FollowServiceTest.java (1)

54-64: 테스트 헬퍼 메서드에서 Avatar ID 하드코딩 주의

createUserWithAvatar 메서드에서 Avatar ID가 항상 1L로 하드코딩되어 있습니다. 여러 사용자에게 아바타를 생성할 때 ID 충돌이 발생할 수 있습니다. 현재 테스트에서는 문제가 없지만, 향후 확장 시 고려가 필요합니다.

💡 개선 제안
-  private User createUserWithAvatar(Long id, String nickname, String avatarImageUrl) {
+  private static long avatarIdCounter = 1L;
+
+  private User createUserWithAvatar(Long id, String nickname, String avatarImageUrl) {
     User user = createUser(id, nickname);
     Avatar avatar = Avatar.builder()
-        .id(1L)
+        .id(avatarIdCounter++)
         .nickname("avatar")
         .imageUrl(avatarImageUrl)
         .user(user)
         .build();

@c5ln c5ln merged commit 9c26165 into develop Feb 4, 2026
6 checks passed
@c5ln c5ln deleted the refactor/175-n1-query branch February 4, 2026 13:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

refactor : N+1 query 수정

1 participant