- Today
- Total
작심삼일
[매일메일] 49. JPA의 N + 1 문제에 대해서 설명해주세요. 본문
이 게시판에서는 매일메일이라는 시스템을 이용해 백엔드를 공부해보고자하는 AI 개발자가 정리해보고자 합니다.
Python이랑 비교하여 이해하기 쉽도록 합니다.
https://www.maeil-mail.kr/question/49
매일메일 - 기술 면접 질문 구독 서비스
기술 면접 질문을 매일매일 메일로 보내드릴게요!
www.maeil-mail.kr
용어 및 질문 이해하기
N+1 문제란, 연관 관계가 설정된 엔티티를 조회할 때, 초기 조회 쿼리(1회) 외에 연관된 엔티티의 수(N)만큼 추가 쿼리가 발생하는 현상이다.
이러한 문제는 글로벌 패치 전략의 설정 방식에 따라 발생 여부와 시점이 달라진다.
글로벌 패치 전략을 즉시 로딩(EAGER) 으로 설정하고 findAll()을 실행하면 N+1 문제가 발생할 수 있다. 이는 findAll()이 내부적으로 select u from User u 형태의 JPQL을 생성하여 실행되기 때문이다. JPQL은 글로벌 패치 전략을 고려하지 않고 단순히 주 엔티티(User)만 조회하는 쿼리를 실행하고, 그 이후에 즉시 로딩 설정을 기반으로 연관 관계에 있는 엔티티들을 각각 추가로 조회한다. 이로 인해 결과적으로 N+1 쿼리가 발생하게 된다.
반대로, 글로벌 패치 전략을 지연 로딩(LAZY) 으로 설정한 경우에는 findAll() 실행 시 연관된 엔티티가 프록시 객체로 주입되므로 처음부터 N개의 쿼리를 추가로 실행하지는 않는다. 이 때문에 표면적으로는 N+1 문제가 발생하지 않는 것처럼 보일 수 있다. 그러나 이후 연관된 데이터를 실제로 접근할 때, 이 프록시 객체가 초기화되면서 추가 쿼리가 실행되며, 결국 N+1 문제가 발생할 수 있다.
결론적으로, N+1 문제는 패치 전략에 따라 발생 시점만 달라질 뿐, 연관된 데이터에 실제로 접근하게 되는 시점에 언제든지 발생할 수 있으므로, Fetch Join, EntityGraph, Batch Fetching 등과 같은 전략적인 해결책이 함께 고려되어야 한다.
답변
이 문제를 해결하기 위해서는 fetch join이나 @EntityGraph를 사용하는 방법이 고려될 수 있다.
fetch join은 연관 관계에 있는 엔티티를 한 번의 쿼리로 함께 조회하도록 하는 JPQL 구문으로, 즉시 로딩을 강제하여 추가 쿼리 발생을 막는 데 효과적이다.
예를 들어 다음과 같은 JPQL을 사용하면, 사용자와 연관된 게시글 데이터를 한 번에 가져올 수 있게 된다.
SELECT DISTINCT u
FROM User u
LEFT JOIN FETCH u.posts
또한, @EntityGraph를 활용하면 별도의 JPQL 작성 없이도 연관 엔티티를 함께 로딩하는 효과를 얻을 수 있다.
쿼리 메서드에 아래와 같이 어노테이션을 설정하면, 지정한 연관 필드가 함께 조회되도록 동작하게 된다.
@EntityGraph(attributePaths = {"posts"}, type = EntityGraph.EntityGraphType.FETCH)
List<User> findAll();
이러한 방식들을 활용하면, 연관 데이터를 효율적으로 로딩할 수 있으며 N + 1 문제를 방지할 수 있게 된다.
'스터디 > AI 개발자가 공부하는 백엔드' 카테고리의 다른 글
[매일메일] 29. 엔티티 매니저에 대해 설명해주세요. (1) | 2025.05.02 |
---|---|
[매일메일] 28. JPA의 ddl-auto 옵션은 각각 어떤 동작을 하고 어떤 상황에서 사용해야 할까요? (0) | 2025.05.01 |
[매일메일] 27. Spring Data JPA에서 새로운 Entity인지 판단하는 방법은 무엇일까요? (1) | 2025.04.30 |