JPA N+1 문제와 Fetch Join 실무 고찰: lazy loading이면 다 해결되나?

lazy loading이면 다 해결되나?

 

서론

 

JPA를 공부하며 연관관계를 설정할 때, 이런 생각이 들었다.

 

“N+1 문제? 그냥 모든 연관관계 FetchType.LAZY로 걸어두면 되는 거 아닌가?”

 

그렇게 생각하고 엔티티마다 LAZY를 설정하고 테스트를 통과시켰다.

하지만 실제 데이터 목록 조회 쿼리가 나갈 때 SQL 로그를 보니 **1번의 쿼리로 10개 게시글을 가져온 뒤, 각 댓글을 가져오느라 10번의 추가 쿼리가 쏘아지는 끔찍한 현상**을 목격했다.

 

이 글은 JPA N+1 문제의 발생 원인과 Fetch Join을 이용해 성능을 극대화한 실무 경험을 담고 있다.

부족한 내용이 있을 수 있지만, 나처럼 막 시작한 사람에게는 도움이 될 거라 생각한다.

 


 

📚 N+1 문제 발생 원인과 해결책

 

N+1 문제는 JPQL이 개별 객체 단위로 지연 로딩을 수행할 때 발생하는 데이터베이스 쿼리 비효율성입니다.

 


 

해결 전략

 

1. Fetch Join (패치 조인)

  • 연관된 엔티티를 한 번의 조인(JOIN) 쿼리로 몽땅 함께 조회해 옴
  • N+1 문제가 근본적으로 발생하지 않음
public interface BoardRepository extends JpaRepository {

    @Query("SELECT b FROM Board b JOIN FETCH b.comments WHERE b.status = 'ACTIVE'")
    List findAllWithComments();
}

 


 

2. @BatchSize 설정

  • 지연 로딩 시 지정한 사이즈만큼 IN 쿼리로 모아서 가져옴
  • 컬렉션 페이징 처리 시 Fetch Join의 중복 데이터 문제를 우회하는 탁월한 방법

 


 

정리하며

 

  • LAZY 설정만으로는 N+1 문제를 막을 수 없으며, 객체 그래프 탐색 시 추가 쿼리가 나간다.
  • 단건 조회에는 Fetch Join, 컬렉션 페이징 조회에는 @BatchSize를 적절히 조합하는 것이 베스트다.

 

SQL 로그를 꼼꼼히 확인하며 JPA 성능을 최적화하는 감각을 키우게 된 경험이었다.

댓글 남기기