JPA에서 Fetch Type, 즉시로딩(Eager)과 지연로딩(Lazy)

Sadie·2023년 9월 6일
0

Spring And JPA

목록 보기
1/9

공부하는 과정에 작성한 글으로 잘못되거나 부족한 부분이 있을 수 있습니다
언제든지 알려주시면 감사하겠습니다


Fetch Type

JPA에서 데이터를 조회할 때(예를 들면 Entity), 연관관계에 있는 객체를 가져오는 방법
즉시로딩(Eager)과 지연로딩(Lazy)이 있다


즉시로딩(Eager)

// Member class 안에 존재
@ManyToOne(fetch = FetchType.EAGER) // 즉시로딩
@JoinColumn(name = "TEAM_ID")
private Team team;

예를 들어 Member라는 class 안에 다음과 같은 코드가 있다고 하자
멤버가 Many이고 팀이 One인 다대일(ManyToOne) 관계가 만들어진다
이런 관계에서 Member를 조회하면 어떻게 될까
이때 fetch type은 eager이다

한방 쿼리로 실체 객체들을 한번에 다 조회해온다


지연로딩(Lazy)

// Member class 안에 존재
@ManyToOne(fetch = FetchType.LAZY) // 지연로딩
@JoinColumn(name = "TEAM_ID")
private Team team;

이번에 fetch type은 lazy이다
이때 Member를 조회하면 어떻게 될까

지연로딩을 주면 JPA가 Team 프록시 객체를 넘겨준다
Member만 조회해오고 연관관계에 있는 나머지 데이터(Team)는 조회를 미룬다
나중에 실제 객체를 사용하는 시점에(get 등으로 Team을 사용하는 시점에) 초기화가 되고 DB에 쿼리가 나간다



장단점

그냥 보기에는 즉시로딩이 한 번에 모두 다 조회해오기 때문에 좋을 수 있다
하지만 즉시로딩은 N+1 문제가 발생할 수 있다

N+1 문제는 쿼리를 1개 날렸는데, 그것 때문에 추가 쿼리가 N개 나간다는 의미이다
예를 들면 Member를 조회하는데 fetch type이 LAZY일 경우, 프록시만 보내지만 fetch type이 EAGER일 경우, 그와 관련된 Team 또한 모두 가져와야한다
다른 객체와의 조인이 많을수록, 멤버의 수가 많을수록 추가 쿼리의 수는 더 늘어나는 문제가 생긴다

이런 N+1 문제의 가장 일반적인 해결책은 fetch 조인이다


이번에는 지연로딩을 생각해보자
위의 예시에서 fetch type을 LAZY로 조회한다면 select 쿼리가 따로따로 2번 나간다

결국 쿼리를 2번씩 날리게 되는 것이니 성능상 손해가 있을 수 있다
이때는 즉시 로딩(EAGER) 전략을 사용해서 함께 조회하면 된다


실무에서는 지연로딩을 권장한다고 한다

@ManyToOne, @OneToOne은 기본이 즉시 로딩이므로 LAZY로 설정해준다
@OneToMany와 @ManyToMany는 기본이 지연 로딩이다



참고

https://velog.io/@jin0849/JPA-%EC%A6%89%EC%8B%9C%EB%A1%9C%EB%94%A9EAGER%EA%B3%BC-%EC%A7%80%EC%97%B0%EB%A1%9C%EB%94%A9LAZY
https://ict-nroo.tistory.com/132

0개의 댓글