일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 알고리즘
- 티스토리챌린지
- 스프링핵심원리
- effectivejava
- 이차전지관련주
- 스프링
- 카카오
- JavaScript
- 김영한
- Spring
- 알고리즘정렬
- 자바
- ElasticSearch
- 자바스크립트
- kubernetes
- java
- 엘라스틱서치
- 스프링부트
- Effective Java 3
- Sort
- 예제로 배우는 스프링 입문
- k8s
- 코딩테스트
- 이펙티브 자바
- Effective Java
- 카카오 면접
- 이펙티브자바
- 스프링 핵심원리
- 클린아키텍처
- 오블완
- Today
- Total
Kim-Baek 개발자 이야기
JPA Fetch 전략과 N+1 문제 본문
Fetch Type 이란
Fetch Type 은 JPA 가 하나의 Entity 를 조회할 때, 연관관계에 있는 객체들을 어떻게 가져올 것이냐를 나타내는 설정값입니다.
Fetch Type 은 크게 Eager 와 Lazy 두가지 전략이 있습니다. Fetch Type Issue 상황이라는 것은 하나의 Entity 를 로드할 때, 아래의 두가지 전략 중 고민하는 상황을 말합니다.
- 연관 관계에 있는 Entity 들 모두 가져온다 → Eager 전략
- 연관 관계에 있는 Entity 가져오지 않고, getter 로 접근할 때 가져온다 → Lazy 전략
N+1 문제는 이럴 때 발생합니다.
ManyToOne, OneToOne 컬럼의 FetchType 을 LAZY 로 하였을 경우 발생합니다.
이렇게 하위 엔티티들을 첫 쿼리 실행시 한번에 가져오지 않고, Lazy Loading으로 필요한 곳에서 사용되어 쿼리가 실행될때 발생하는 문제가 N+1 쿼리 문제입니다.
언제 발생하는가?
다음의 예제 엔티티 클래스들과 함께 설명을 진행해보겠다.
마스터와 학생은 일대다 관계를 갖고 있다. 한 마스터가 여러명의 학생을 관리하고 있고, 양방향 연관관계가 수립되어 있다.
@Entity
public class Master {
@Id
@GeneratedValue
private long id;
@OneToMany
private List<Student> students = Lists.newArrayList();
...
}
@Entity
public class Student {
@Id
@GeneratedValue
private long id;
@ManyToOne
private Master master;
...
}
아래는 마스터들을 조회할 수 있는 레포지토리 인터페이스이다.
public interface MasterRepository extends JpaRepository<Long, Master> {
(JPA 레포지토리가 기본 제공해주는 메소드들이 당연히 포함되어 있다.)
}
이 상황에서 MasterRepository.findAll() 을 실행했을 때, 우리는 이런 쿼리가 날라가길 기대할 것이다.
SELECT * FROM MASTER
LEFT JOIN STUDENT
ON STUDENT.MASTER_ID = MASTER.ID
현실은…..
SELECT * FROM MASTER
SELECT * FROM STUDENT WHERE MASTER_ID = 0
SELECT * FROM STUDENT WHERE MASTER_ID = 1
SELECT * FROM STUDENT WHERE MASTER_ID = 2
SELECT * FROM STUDENT WHERE MASTER_ID = 3
...
DB에 상당한 부하를 일으키게 된다.
1. Join Fetch
1번째는 join fetch를 사용하는 것입니다.
2. @EntityGraph
2번째 방법은 @EntityGraph을 사용하는 것입니다.
oinFetch는 Inner Join, Entity Graph는 Outer Join이라는 차이점이 있음을 주의해주세요.
공통적으로 카테시안 곱(Cartesian Product)이 발생하야 중복이 발생한다.
해결하기 위해서, set을 쓰거나 쿼리에 distinct 쓰자
글로벌 페치 전략 기본값
- @OneToOne, @ManyToOne : EAGER
- @OneToMany, @ManyToMany : LAZY
즉시 로딩이 필요하지 않은 @OneToOne, @ManyToOne 연관관계에 대해서는 글로벌 페치 전략을 LAZY로 변경해서 불필요한 쿼리 실행 방지
'개발' 카테고리의 다른 글
[카카오 면접] Garbage Collector 의 여러 방법 (0) | 2020.08.07 |
---|---|
[카카오 면접] Blocking I/O, Syncronous Non-Blocking I/O, Asyncronous Non-Blocking I/O (1) | 2020.08.06 |
JPA와 Spring Data JPA (0) | 2020.08.05 |
JPA란? ORM vs SQL Mapper (0) | 2020.08.04 |
JPA 트랜잭션의 전파 및 격리 (0) | 2020.08.04 |