우당탕탕
[Spring] JPA N+1 문제 해결법 ( 원인부터 해결까지 ) 본문
JPA N+1 문제 해결법
이번 포스팅에서는 JPA에서 자주 발생하는 성능 이슈인 N+1 문제와 이를 해결하는 방법들을 정리해 보려고 합니다.
N+1 문제란?
N+1 문제란, JPA로 엔티티를 조회할 때 연관된 엔티티를 추가로 조회하면서 불필요하게 많은 쿼리가 실행되는 현상을 말합니다. 예를 들어, 게시글 10개를 조회할 때 각 게시글의 작성자 정보를 연관엔티티로 가져온다면, 게시글 목록(10개의 게시글)을 가져오는 쿼리 1번 + 작성자 정보(게시글당 1번씩) 쿼리 10번, 총 11번의 쿼리가 실행되는 것이 대표적인 N+1 문제입니다.
N+1 문제가 왜 생길까?
JPA에서 연관된 엔티티는 기본적으로 지연로딩(LAZY) 방식입니다. 즉, 실제로 해당 데이터를 사용할 때마다 추가 쿼리가 실행되는 방식입니다.
N+1 문제 해결법
1. Fetch Join 사용하기
Fetch Join 사용은 가장 많이 사용되는 방법입니다. JPQL에서 Fetch Join을 사용하면 연관된 데이터를 한 번의 쿼리로 가져올 수 있습니다.
@Query("select t from Team t join fetch t.members")
List<Team> findAllWithMembers();
장점: 한 번의 쿼리로 모든 데이터 조회 가능
단점: 1:N 관계에서 중복 데이터가 생길 수 있고, 페이징에서 사용이 제한됨
2. @EntityGraph 사용하기
@EntityGraph는 JPA에서 제공하는 기능으로, 복잡한 JPQL 없이도 연관 데이터를 한 번에 가져올 수 있습니다.
@EntityGraph(attributePaths = {"members"})
List<Team> findAll();
단점: 복잡한 쿼리에서는 한계가 있음
3. Batch Size 설정하기
JPA 설정이나 어노테이션으로 한 번에 여러 연관 데이터를 IN 쿼리로 묶어서 가져오는 방법입니다.
@BatchSize(size = 100)
@OneToMany(mappedBy = "team")
private List<Member> members;
장점: 쿼리 수를 줄일 수 있으며, 페이징과 함께 사용 가능
단점: 쿼리가 완전히 1번만 실행되지는 않음 ( IN 쿼리로 여러 개씩 묶어서 실행 )
4. SUBSELECT 전략
Hibernate에서 지원하는 방식으로, 메인 데이터를 먼저 조회한 뒤 연관데이터는 한 번의 서브쿼리로 가져오는 방식입니다.
@OneToMany(fetch = FetchType.LAZY)
@Fetch(FetchMode.SUBSELECT)
private List<Member> members;
장점: N+1문제 해결, 페이징과 함께 사용 가능
단점: 데이터가 너무 많으면 성능 저하가 발생할 수 있음
상황별 사용 전략
연관 데이터까지 한 번에 조회 | fetch join, @EntityGraph |
페이징이 필요할 때 | Batch Size, SUBSELECT |
연관 데이터가 아주 많을 때 | Batch Size, SUBSELECT, 또는 DTO로 분리 조회 |
마무리
N+1 문제는 JPA를 쓴다면 꼭 한 번은 마주치는 문제입니다. 쿼리 로그를 꼭 확인하면서, 불필요하게 쿼리가 반복되는 것 같다면 위 방법들 중 하나를 적용해서 해결해 보세요!
개인적으로는 단순 조회 시에는 Fetch Join , 페이징이 필요하다면 @EntityGraph나 Batch Size 방법을 추천드립니다.
'Tech > Spring' 카테고리의 다른 글
[Spring] JPA Auditing을 활용한 생성일, 수정일 자동 관리하기 (0) | 2025.04.27 |
---|---|
[Spring] 대용량 트래픽을 위한 스프링 튜닝 팁 feat. 실무에서 바로 쓰는 전략 (0) | 2025.04.26 |
스프링 외부 API 호출 방법 비교: RestTemplate, WebClient, FeignClient, RestClient (0) | 2025.04.14 |
JPA vs MyBatis: 어떤 ORM을 선택해야 할까? (0) | 2025.04.10 |
[Spring] 스프링 @Transactional(트랜잭션)에 대해 이해하기 (0) | 2024.09.23 |