언어

JPA에서 즉시 로딩(EAGER)과 지연 로딩(LAZY)은 왜 중요할까?

zumsim 2025. 6. 13. 23:09
728x90
반응형

💡 JPA에서 즉시 로딩(EAGER)과 지연 로딩(LAZY)은 왜 중요할까?

우리가 JPA를 사용할 때 가장 자주 마주치는 개념 중 하나가 즉시 로딩(EAGER)지연 로딩(LAZY) 이다.
이 둘의 차이를 알지 못한 채 개발을 진행하면, 언젠가는 의도치 않은 N+1 문제를 만나게 된다.

오늘은 이 두 개념의 차이를 이해하고, 언제 어떤 전략을 선택해야 할지에 대한 나의 생각을 정리해본다.


🔍 즉시 로딩과 지연 로딩이란?

JPA에서 연관 관계를 맺을 때, 하위 엔티티를 언제 로딩할지를 지정할 수 있다.
기본적으로는 다음 두 가지 방식이 존재한다.

java
복사편집
@OneToMany(fetch = FetchType.LAZY) private List<Order> orders;
  • EAGER (즉시 로딩): 연관된 엔티티를 즉시 조회
  • LAZY (지연 로딩): 연관된 엔티티를 실제로 접근할 때 조회

⚙️ 차이점 비교

구분EAGER (즉시 로딩)LAZY (지연 로딩)
조회 시점 엔티티 조회와 동시에 연관 엔티티도 조회 실제 필드에 접근할 때 쿼리 발생
성능 필요 없는 쿼리까지 발생 가능 초기 로딩이 가볍고 유연
주의점 N+1 문제 위험 ↑ LazyInitializationException 주의 필요
 

❗ N+1 문제란?

예를 들어, 다음과 같은 구조가 있다고 해보자.

java
복사편집
@Entity public class Member { @ManyToOne(fetch = FetchType.EAGER) private Team team; }

이제 모든 Member 리스트를 조회해보면?

java
복사편집
List<Member> members = memberRepository.findAll();
  • 이때 @ManyToOne(fetch = EAGER) 이면 각 Member에 대해 Team을 조회하는 쿼리가 별도로 발생한다.
  • 만약 Member가 100명이면? → 1 + 100 = 101번 쿼리가 발생하게 된다.

바로 이게 N+1 문제다.
EAGER는 개발자가 제어할 수 없다는 점에서 특히 위험하다.


✅ 그래서 뭘 써야 할까?

JPA에서는 대부분의 연관 관계를 기본적으로 LAZY로 설정하는 걸 추천한다.
그 이유는 단 하나. 개발자가 언제 로딩할지 직접 제어할 수 있기 때문이다.

java
복사편집
@ManyToOne(fetch = FetchType.LAZY) private Team team;

그럼 실제로 팀 이름을 출력하고 싶을 때만 쿼리를 날리게 된다.


👀 실무 경험에서 느낀 점

  • 초기에 무지하게 EAGER로 설정해두고 개발했는데, 서비스 속도가 이상하게 느려졌다.
  • JMeter로 테스트하니 무려 300개 이상의 쿼리가 날아가고 있었음.
  • LAZY로 바꾸고 나니 전체 쿼리 수가 절반 이하로 줄었고, 응답 속도도 빨라졌다.
  • 단, LAZY는 트랜잭션 범위를 벗어나면 LazyInitializationException이 터지기 때문에, 서비스 단에서 연관 데이터를 다 쓰도록 설계해야 한다.

✍️ 정리하며

  • EAGER는 위험하다. 내가 원하지 않는 시점에 쿼리를 발생시킨다.
  • LAZY는 제어권이 개발자에게 있다. 설계만 잘하면 성능도 좋고 관리도 쉽다.
  • 기본은 LAZY, 정말 필요한 곳에만 fetch join이나 DTO Projection 등을 활용하자.

📚 참고 자료

728x90
반응형