Kim ByeungHyun
N+1 문제 본문
N + 1 문제가 무엇인가?
N + 1 문제는 데이터베이스에서 발생하는 성능 이슈 중 하나입니다. 이 문제는 특정 레코드를 조회 할 때, 그 레코드와 연관된 다른 레코드들을 함께 조회하는 경우 발생합니다.
예를 들어, 게시물을 저장하는 데이터베이스에서 각 게시물은 해당 게시물을 작성한 사용자의 정보를 참조 할 수 있습니다. 이때, 게시물을 조회할 때 해당 게시물의 작성자 정보도 함께 조회하게 되는데, 이때 작성자 정보가 중복해서 조회되는 경우를 N+1 문제라고 합니다.
N + 1 쿼리 문제의 원인?
Spring Data JPA에서 제공하는 Repository의 findAll(), findById() 등과 같은 메소드를 사용하면 바로 DB에 SQL 쿼리를 날리는 것이 아닙니다.
JQL이라는 객체지향 쿼리 언어를 생성, 실행시킨 후 JPA는 이것을 분석해서 SQL을 생성, 실행하는 동작에서 N+1 문제가 발생합니다.
JPQL 입장에서는 LAZY로딩, EAGER로딩과 같은 글로벌 패치 전략을 신경쓰지 않고 JPQL만 사용해서 SQL을 생성합니다.
JPQL이란 플랫폼에 독립적인 객체지향 쿼리 언어 입니다.
자바 코드에서 데이터베이스를 조회할 때 특정 SQL이나 저장 엔진에 종속되지 않게 도와줍니다.
N + 1 쿼리 문제는 언제 발생 할까?
발생하는 경우는 2가지 경우가 있습니다.
두 개의 엔티티가 1:N 관계를 가지며 JPQL로 객체를 조회할 떄
1. EAGER 전략으로 데이터를 가져오는 경우
2. LAZY 전략으로 데이터를 가져온 이후에 가져온 데이터에서 하위 엔티티를 다시 조회하는 경우
Spring 해결
예를 들어, 학생(N)과 팀(1)에서 양방향관계를 갖고 DB에서 팀을 10개를 꺼낸다고 가정해보자.
첫 쿼리는 팀 10개를 꺼내는 쿼리가 하나의 쿼리가 나가게 되고 이때, 팀 기준 OneToMany이므로 Lazy로 동작하여 학생은 프록시로 들어오게 된다. 이게 가져온 각각의 팀에 대해 학생들에게 접근하는 로직이 있다면 각 팀마다 학생들을 조회하는 쿼리가 1개씩 더 나가게 된다. 즉, 10개의 쿼리가 더 나가게된다.
이에 대한 해결책은 Fetch Join과 Batch Size가 있다.
Fetch Join을 사용하면 Lazy로딩으로 프록시로 들어오던 것을 join으로 한 번에 땡겨올 수 있다.
Batch Size는 N+1문제가 발생하던 것 처럼 프록시로 가져오고 학생들 가져오게 될 때 쿼리가 한번 더 나가게 되는데 이때 in쿼리로 Batch size 개수만큼 가져온다.
가져온 팀이 10개이고 Batch size가 5라면, 최초에 학생을 가져오는 쿼리에서 where 조건문 in 쿼리로 5개의 team id값을 넣어서 쿼리를 날린다. 이렇게 되면 결과적으로 학생을 가져오는 쿼리는 2번이 나가게 되어 총 쿼리는 3(팀 가져오는 쿼리 + 학생 가져오는 쿼리)개의 쿼리가 나가게 된다.
참고로 @EntityGraph를 사용해도 Fetch join으로 가져올 수 있다.
1. 패치 조인(Fetch Join)
미리 쿼리로 테이블을 조인해서 가져오기 때문에 LAZY, EAGER 두개의 전략에 해당되는 해결법 입니다.
@Query("select DISTINCT a from 테이블A a join fetch a.테이블B")
List<테이블A> findAllJoinFetch();
단점 :
- JPA가 제공하는 Pageable 기능 사용 불가 (페이징API)
- 1:N 관계가 2개인 엔티티를 패치 조인 사용 불가 (임시 해결법은 List -> Set으로 자료구조를 변경하는 것)
2. Batch Size 조절
설정한 Size 만큼 데이터를 미리 로딩합니다. (where in 을 사용하여)
JPA의 페이징 API 기능처럼 개수가 고정된 데이터를 가져올 떄 함께 사용할 때 사용 가능할 듯합니다.
@BatchSize(size = 5)
@OneToMany(mappedBy = "테이블A", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private List<테이블B> 테이블Bs = new ArrayList<>();
https://vladmihalcea.com/n-plus-1-query-problem/
'공부 > Database' 카테고리의 다른 글
JDBC, SQL Mapper, ORM (0) | 2023.04.06 |
---|