Sparta/Projects

[Project] 주특기 심화 - 트러블 슈팅

syuare 2025. 6. 12. 14:00

 

1. N+1 문제 발생 시키고자 하는 테스트 코드로 해당 문제가 발생하지 않는 문제 (해결 X)

발생 상황

  • 프로젝트 레벨 2 가 N+1 문제 해결을 위한 리팩토링 문제인데,
  • 프로젝트 요구사항은 아니지만 N+1 문제에 대해 직접적으로 확인하여 이해하고자 테스트 코드를 구현 시도

테스트를 위한 기본 세팅

// 테스트 세팅

@Autowired
private TodoRepository todoRepository;

@Autowired
private UserRepository userRepository;

@Autowired
EntityManagerFactory emf;

@BeforeEach
void setUp() {

    // User, Todo 5개 생성
    for (int i=1; i<=5; i++) {
    User user = new User("test" + i + "@email.com", "pw123", UserRole.USER);
    userRepository.save(user);

    Todo todo = new Todo("테스트 제목" + i, "테스트 내용" + i, "테스트 날씨", user);
    todoRepository.save(todo);
    }
}

N+1 문제 발생 시키기 위한 테스트 코드

  • 기대 결과: 쿼리가 user의 email을 가져올 때 마다 쿼리가 실행되는 것을 기대함
  • 구현 결과
    • 기대 결과와는 다르게 쿼리를 반복적으로 실행되지 않음을 확인
    • 쿼리 수를 확인할 수 있는 코드도 추가하였으나 쿼리 수 2회로 큰 의미가 없었음
// 기존 코드 > 테스트 코드를 위해 코드 삭제 X
@Query("SELECT t FROM Todo t LEFT JOIN t.user u ORDER BY t.modifiedAt DESC")
Page<Todo> findAllByOrderByModifiedAtDesc(Pageable pageable);
/**
* N+1 테스트 -> 에러 발생
*/
@Test
void nPlusOneError() {

    // 쿼리 수 확인
    SessionFactory sf = emf.unwrap(SessionFactory.class);
    sf.getStatistics().setStatisticsEnabled(true);

    System.out.println("===== N+1 문제 발생 테스트 =====");
    Page<Todo> todos = todoRepository.findAllByOrderByModifiedAtDesc(PageRequest.of(0,5));

    for (Todo todo : todos) {
        System.out.println("제목: " + todo.getTitle());
        System.out.println("유저이메일: " + todo.getUser().getEmail());
    }

    System.out.println("쿼리 실행 수: " + sf.getStatistics().getPrepareStatementCount());

    System.out.println("===== N+1 문제 발생 테스트 종료 =====");

}

 

회고

  • 시간이 부족해서 해당 테스트 코드를 개선하지 못하였다.
  • 아직까지 N+1 문제에 대해 정확히 이해를 하지 못하였다.
  • 조금 더 공부가 필요함을 느꼈다.