[TIL] 23.05.30 Spring Data Jpa(3) 복습 @EntityGraph, fetch join

hyewon jeong·2023년 6월 1일
0

TIL

목록 보기
128/138

1. 연관관계 시 N+1 최적화

쿼리 방식 선택 권장 순서
1. 우선 엔티티를 DTO로 변환하는 방법을 선택한다.
2. 필요하면 페치 조인으로 성능을 최적화 한다. 대부분의 성능 이슈가 해결된다.
컬렉션 최적화 ( 컬렉션 페치조인 사용시 페이징을 함께 사용 불가하다)

  • 페이징 필요 : hibernate.default_batch_fetch_size , @BatchSize 로 최적화
  • 페이징 필요X : 페치 조인 사용
  1. 그래도 안되면 DTO로 직접 조회하는 방법을 사용한다.
  • new 명령어를 사용해서 JPQL의 결과를 DTO로 즉시 변환
  • SELECT 절에서 원하는 데이터를 직접 선택하므로 DB 애플리케이션 네트웍 용량 최적화(생각보다 미비)
  • 리포지토리 재사용성 떨어짐, API 스펙에 맞춘 코드가 리포지토리에 들어가는 단점
  1. 최후의 방법은 JPA가 제공하는 네이티브 SQL이나 스프링 JDBC Template을 사용해서 SQL을 직접
    사용한다.
  • 1:N 관계에서 fetcytype = Lazy 로 설정 할것 ,N+1 을 해결하기 위해 컬렉션 조회의 경우 fetch Join 을 하면 페이징 처리를 할수 없으므로, betch_size 를 통해 , where in절로 필요한 컬렉션 데이터를 한번에 가져오게 한다. (컬렉션에서 fetch join을 하면 데이터의 수가 증가하여 페이징(limit)으로는 페이징 처리가 어려워 메모리에 데이터를 다 가져와 jpa가 계산하므로… memory error 발생한다. )
  • N:1 관계에서는 Fetch join 과 함께 페이징도 가능하다.
  • @EntityGraph 는 fetch join 과 동일한 가능인데 간단할때는 @EntityGraph(쿼리메서드를 사용하면서 페치 조인을 하고 싶을 때) 를 사용하고 , 대부분은 fetch join으로 성능최적화를 한다.
    • 연관된 엔티티들을 SQL 한번에 조회하는 방법

1-1. hibernate.default_batch_fetch_size , @BatchSize 로 최적화

최적화 옵션


spring: jpa:
      properties:
        hibernate:
          default_batch_fetch_size: 1000
  • 개별로 설정하려면 @BatchSize 를 적용하면 된다. (컬렉션은 컬렉션 필드에, 엔티티는 엔티티 클래스에 적용)
  • 페치 조인 방식과 비교해서 쿼리 호출 수가 약간 증가하지만, DB 데이터 전송량이 감소한다.
  • 컬렉션 페치 조인은 페이징이 불가능 하지만 이 방법은 페이징이 가능하다.

    참고: default_batch_fetch_size 의 크기는 적당한 사이즈를 골라야 하는데, 100~1000 사이를 선택하는 것을 권장한다. 이 전략을 SQL IN 절을 사용하는데, 데이터베이스에 따라 IN 절 파라미터를 1000으로 제한하기도 한다. 1000으로 잡으면 한번에 1000개를 DB에서 애플리케이션에 불러오므로 DB 에 순간 부하가 증가할 수 있다. 하지만 애플리케이션은 100이든 1000이든 결국 전체 데이터를 로딩해야 하므로 메모리 사용량이 같다. 1000으로 설정하는 것이 성능상 가장 좋지만, 결국 DB든 애플리케이션이든 순간 부하를 어디까지 견딜 수 있는지로 결정하면 된다.

코드

public interface MemberRepository extends JpaRepository<Member,Long>(){
 //페치 조인
  @Query("select m from Member m left join fetch m.team t")
  List<Member> findMemberFetchJoin();

  //@EntityGraph 이용
  //findAll()은 CrudRepository의 기능으로 JpaRepository 상위 기능이다. 그래서 사용 하기 위해 @Override 한다.
  @Override
  @EntityGraph(attributePaths = {"team"}) // 위와 동일하다.
  List<Member> findAll();
  
  // 회원을 조회 할 때 팀관련 사항도 필요한 경우 
  @EntityGraph(attributePaths = {"team"})
  List<Member> findByUsername(@Param("Username")String username);
  
  // 페치 조인 + @EntityGraph  사용
  @EntityGraph(attributePaths = {"team"})
  @Query("select m from Member m ")
  List<Member> findFetchJoinAndEntityGraph();

}
  • EntityGraph 정리
    사실상 페치 조인(FETCH JOIN)의 간편 버전
    LEFT OUTER JOIN 사용

참고
김영한 Spring Data Jpa 강의 자료
김영한 실전 스프링 부트와 Jpa 활용(2)

profile
개발자꿈나무

0개의 댓글