-
1. 지연 로딩(Lazy Loading)과 즉시 로딩(Eager Loading)
JPA에서 @OneToMany, @ManyToOne, @OneToOne, @ManyToMany 같은 연관관계를 설정하면 연관된 엔티티를 언제 가져올지를 설정해야 한다. 이를 결정하는 것이 fetch 속성이다. 기본값은 연관관계에 따라 다르다.
1.1 즉시 로딩(Eager Loading)
즉시 로딩은 엔티티를 조회할 때 연관된 엔티티도 함께 가져오는 방식이다.
@Entity public class Member { @Id @GeneratedValue private Long id; @ManyToOne(fetch = FetchType.EAGER) // 즉시 로딩 private Team team; }
즉시 로딩(FetchType.EAGER)을 설정하면 Member 엔티티를 조회할 때 Team도 즉시 같이 조회된다.
SELECT * FROM member m JOIN team t ON m.team_id = t.id WHERE m.id = ?;
📌 즉시 로딩의 단점
- 필요하지 않은 연관 데이터를 함께 가져온다.
- 쿼리가 복잡해질 가능성이 높다.
- 성능 저하 가능성이 있다.
즉시 로딩은 필요한 경우가 아니면 사용하지 않는 것이 좋다.
1.2 지연 로딩(Lazy Loading)
지연 로딩은 연관된 엔티티를 실제로 사용할 때 가져오는 방식이다.
@Entity public class Member { @Id @GeneratedValue private Long id; @ManyToOne(fetch = FetchType.LAZY) // 지연 로딩 private Team team; }
이제 Member 엔티티를 조회해도 Team은 바로 가져오지 않고, 실제로 getTeam()을 호출할 때 쿼리가 실행된다.
Member member = em.find(Member.class, 1L); // 여기서는 Team 조회 X Team team = member.getTeam(); // 여기서 Team 조회 쿼리 실행
SELECT * FROM member WHERE id = ?; -- member 조회 SELECT * FROM team WHERE id = ?; -- team 조회 (필요할 때 실행)
📌 지연 로딩의 장점
- 필요한 데이터만 조회하여 성능을 최적화할 수 있다.
- 불필요한 쿼리 실행을 줄일 수 있다.
연관된 엔티티를 많이 조회하는 경우에는 N+1 문제가 발생할 수 있다.
2. N+1 문제
Member 엔티티 리스트를 가져올 때 각 Member가 Team을 가지고 있다면 아래와 같이 쿼리가 실행될 수 있다.
List<Member> members = em.createQuery("SELECT m FROM Member m", Member.class).getResultList();
SELECT * FROM member; -- 1개의 쿼리 실행 (N개의 Member 조회) SELECT * FROM team WHERE id = ?; -- N개의 Member에 대해 N번 실행
1개의 Member 리스트를 가져오는 쿼리 1번 +
각 Member의 Team을 가져오는 N번의 추가 쿼리 → 총 N+1개의 쿼리 실행📌 N+1 문제의 해결 방법
- Fetch Join 사용
- Entity Graph 사용
- Batch Size 설정
N+1 문제 어떻게 해결해야할까
3. N+1 문제 해결 방법
3.1 Fetch Join 사용
JOIN FETCH를 사용하면 한 번의 쿼리로 필요한 데이터를 모두 조회할 수 있다.
List<Member> members = em.createQuery( "SELECT m FROM Member m JOIN FETCH m.team", Member.class ).getResultList();
SELECT * FROM member m JOIN team t ON m.team_id = t.id;
Fetch Join의 장점
- N+1 문제를 해결할 수 있다.
- 쿼리 실행 횟수를 최소화하여 성능을 개선할 수 있다.
3.2 Entity Graph 사용
JPA의 @EntityGraph를 활용하면 지연 로딩을 유지하면서 특정 상황에서만 즉시 로딩을 적용할 수 있다.
@EntityGraph(attributePaths = {"team"}) @Query("SELECT m FROM Member m") List<Member> findAllWithTeam();
'CS > 웹개발' 카테고리의 다른 글
Handlebars.js vs Thymeleaf (0) 2025.03.19 React (0) 2025.03.18 데이터 빠르게 찾기 - 인덱스 설정하기 (0) 2025.03.12 TDD (0) 2025.01.23 Docker (0) 2025.01.20 댓글