트러블 슈팅 - N+1 문제

Zyoon·2025년 6월 20일

트러블슈팅

목록 보기
6/11
post-thumbnail

❗FetchJoin 부재로 인한 N+1 문제


기존 코드

List<Log> logs = queryFactory
        .selectFrom(log)
        .leftJoin(log.user, user) // ← 일반 join
        .where(...)
        .fetch()
  • QueryDSL을 사용해 Log 엔티티에서 User 엔티티를 join하여 데이터를 조회한다.

문제점

  • 하지만 위와 같이 단순히 join만 사용하면 N+1 문제가 발생할 수 있다.
  • fetchJoin() 없이 leftJoin()만 사용하는 경우:
    1. Log 리스트는 한 번의 쿼리로 조회되지만,
    2. 이후 log.getUser().getUsername() 같은 메서드를 호출하는 시점에,
    3. 연관된 User 엔티티를 가져오기 위해 추가 쿼리가 발생 → N+1 문제 유발
  • 예를 들어 Log가 10개면, User 조회를 위한 쿼리가 최대 10번 추가로 실행될 수 있다.

Fetch Join이란?

  • fetchJoin()은 연관된 엔티티를 조인과 동시에 즉시 로딩하는 기능이다.
  • 즉, Log 10개와 각각의 User한 번의 쿼리로 모두 불러오기 때문에 이후 log.getUser()를 호출해도 추가 쿼리가 발생하지 않는다.

해결 방법

List<Log> logs = queryFactory
        .selectFrom(log)
        .leftJoin(log.user, user).fetchJoin() // ← fetchJoin 추가
        .where(...)
        .fetch();
  • fetchJoin()을 사용하면 LogUser한 번의 쿼리로 함께 조회할 수 있다.
  • 이후 log.getUser() 호출 시에도 DB에 추가 쿼리가 발생하지 않아, N+1 문제가 해결된다.
  • 따라서 연관 엔티티가 필요한 경우, fetchJoin()은 성능 최적화를 위한 필수 요소이다.

참고 사항

  • fetchJoin()페이징 처리와 함께 사용할 경우 주의가 필요하다. (예: count 쿼리 이상 등) → 이럴 땐 @EntityGraph 사용도 고려할 수 있다.
profile
기어 올라가는 백엔드 개발

0개의 댓글