본문 바로가기
JPA

[JPA] Fetch type, N+1 문제

by qoth_0 2024. 5. 23.
728x90
반응형

 

Fetch type

Entity를 영속성 컨텍스트에서 사용할 때 연관 Entity 설정

 

1. EAGER(즉시 로딩)

특정 엔티티를 조회할 때 연관된 모든 엔티티를 같이 조회

연관 관계 Entity를 영속성 컨테이너로 전부 즉시 가져옴

 

2. LAZY(지연 로딩)

엔티티가 실제 사용될 때까지 데이터베이스 조회를 지연

 

LAZY가 보편적 권장 사항

Fetch type은 default로 ~ToMany에서는 LAZY~ToOne에서는 EAGER로 지정되어 있음(그래도 명시해주는 게 좋음)

 

N+1 문제란?

연관 관계를 가진 엔티티를 조회할 때 한 번의 쿼리로 연관된 엔티티들을 함께 가져오지 않고, 각 엔티티를 접근할 때마다 추가적인 쿼리가 발생하는 현상

→  예상보다 많은 수의 쿼리가 데이터베이스에 전송되어 성능 저하 발생

 

예를 들어, Post 엔티티에서 Comment 엔티티로의 관계가 1대 N 관계로 Post 엔티티를 find하면

 [1회]  Post 엔티티를 먼저 select 한 후

 [N회]  Post의 id를 이용해서 from comment  where post _id = id Comment 테이블에서 id 개수만큼 select

 

발생하는 이유

일반적으로 findById에 대한 메소드는 EntityManager에서 PK 값을 찍어서 사용하기 때문에 JPA가 내부적으로 Inner Join을 사용하여 최적화를 해주기 때문에 문제가 되지 않음

 

문제는 JPQL

JpaRepository에 정의한 인터페이스 메서드를 실행하면 JPA는 메서드 이름을 분석해서 JPQL을 생성하여 실행함

JPQL은 SQL을 추상화한 객체지향 쿼리 언어로서 특정 SQL에 종속되지 않고 엔티티 객체와 필드 이름을 가지고 쿼리를 실행

→ findAll()이나 findBy~() 메소드를 수행하였을 때 해당 엔티티를 조회하는 select *(~) from post 쿼리만 실행하게 되는 것

 

JPQL 입장에서는 연관관계 데이터를 무시하고 해당 엔티티 기준으로 쿼리를 조회하기 때문

→ 그렇기 때문에 연관된 엔티티 데이터가 필요한 경우, FetchType으로 지정한 시점에 추가 조회

 

FetchType.LAZY나 FetchType.Eager나 모두 발생

다만, Post 엔티티를 조회할 때 발생하는지(Eager) Post 엔티티에서 Comment 엔티티로 접근할 때 발생하는지(Lazy)의 차이일 뿐

 

 

해결 방법

    1. Fetch Join 사용

 

N+1 문제 자체가 한쪽 테이블만 조회하고 연결된 다른 테이블은 따로 조회하기 때문

→ 두 테이블을 JOIN 하여 한 번에 모든 데이터를 가져오면 됨

 

JPQL에서 join fetch(Inner Join) 구문을 사용하여 연관된 엔티티들을 처음 쿼리할 때 함께 가져올 수 있음

@Query("select distinct p from Post p join fetch p.comments")
List<Post> findAllJPQLFetch();

 

    2. Entity Graph 사용

 

Entity Graph를 사용하여 조회 시점에 엔티티의 어떤 속성을 함께 가져올지 명시적으로 지정

@EntityGraph(attributePaths = {"comments"})
@Query("select distinct p from Post p")
List<Post> findAllEntityGraph();

 

 

fetchjoin도 페이징처리를 하면 n+1 발생 -> batch size 조정(추가예정)

 

 

 

 

참고

https://komas.tistory.com/91

https://hoestory.tistory.com/45

https://s-y-130.tistory.com/184

https://velog.io/@jinyoungchoi95/JPA-%EB%AA%A8%EB%93%A0-N1-%EB%B0%9C%EC%83%9D-%EC%BC%80%EC%9D%B4%EC%8A%A4%EA%B3%BC-%ED%95%B4%EA%B2%B0%EC%B1%85

 

728x90
반응형

'JPA' 카테고리의 다른 글

[JPA] JPQL과 방언(Dialect)  (0) 2024.05.27
[JPA] 영속성 전이 : CASCADE  (0) 2024.05.23