N + 1 문제란?

  • 연관 관계에서 발생하는 이슈로 연관 관계가 설정된 엔티티를 조회할 경우 조회된 데이터 갯수(n) 만큼 연관관계의 조회 쿼리가 추가로 발생하여 데이터를 읽어오게 되는 문제.

왜 발생하는 것인가?

  • jpaRepository에 정의한 인터페이스 메서드를 실행하면 JPA는 메서드 이름을 분석하여 JPQL을 생성하여 실행하게된다.
  • JPQL은 SQL을 추상화한 객체지향 쿼리 언어로서 특정 SQL에 종속되지 않고 엔티티 객체와 필드 이름을 가지고 쿼리를 한다.
  • 그렇기 때문에 JPQL은 findAll()이란 메서드를 수행하였을 때 해당 엔티티를 조회하는 select * from table 쿼리만 실행하게 된다.
  • JPQL 입장에서는 연관관계 데이터를 무시하고 해당 엔티티 기준으로 쿼리를 조회
  • 그렇기 때문에 연관된 엔티티 데이터가 필요한 경우, FetchType으로 지정한 시점에 별도로 호출하게 된다.

해결방안

Fetch join

  • 사용자가 원하는것은 join 코드 일 것
  • 최적화된 쿼리를 우리가 직접 사용할 수 있음 → Fetch join
  • JpaRepository에서 제공해주는 것은 아니고 JPQL로 작성해야 한다.
  • ex)
@Query("select o from Owner o join fetch o.cats")
List<Owner> findAllJoinFetch();
  • 연관관계의 연관관계가 있을 경우에도 하나의 쿼리 문으로 표현할 수 있으므로 유리하다.
  • 데이터 호출 시점에 모든 연관 관계의 데이터를 가져오기 때문에 FetchType을 Lazy로 해놓는 것이 무의미해짐

EntityGraph

  • @EntityGraph의 attributePaths에 쿼리 수행시 바로 가져올 필드명을 지정하면 Lazy가 아닌 Eager 조회로 가져오게 된다.
  • Fetch join과 동일하게 JPQL을 사용하여 query문을 작성하고 필요한 연관관계를 EntityGraph에 설정하면 된다.
  • Fetch join과는 다르게 join문이 outer join으로 실행된다. ( Fetch join == inner join)
  • ex
@EntityGraph(attributePaths = "cats")
@Query("select o from Owner o")
List<Owner> findAllEntityGraph();

컬렉션 Fetch join

  • 컬렉션 fetch join은 일대다 관계에서 사용할 수 있으며 데이터가 많아질 수 있다.
    • DISTINCT로 중복 제거가 가능
    • SQL의 DISTINCT
      • ROW가 완벽히 일치해야 중복 제거
    • JPQL의 DISTINCT
      • SQL의 DISTINCT 기능 뿐만 아니라 동일한 엔티티면 중복 제거
        • application단에서 엔티티 중복을 제거한다.

Fetch join의 한계와 극복

  • 컬렉션을 fetch join 하면 페이징 API를 사용할 수 없다.
    • 일대일, 다대일 같은 단일 값 연관 필드들은 페치 조인을 해도 페이징이 가능하다.
    • HIbernate는 경고로그를 남기며 메모리에서 페이징을 한다.
    • 전체 데이터를 가져와 메모리에 올려놓고, 메모리에서 N개씩 데이터를 결과로 보여준다. 자칫 OutOfMemory가 발생할 수 있고, 성능에 영향을 줌

xxxToOne 관계를 모두 페치조인 한다.

  • toOne관계는 row수를 증가시키지 않기 때문
  • 컬렉션은 지연로딩으로 조회

@컬렉션은 지연로딩으로 설정 → Batch_fecth_size를 사용

  • hibernate.default.batch_fetch_size(글로벌 설정)
  • @BatchSize(디테일 설정)
  • 프록시 객체를 설정한 size만큼 in 쿼리로 조

'Computer science > Spring' 카테고리의 다른 글

@Transactional  (0) 2023.06.15
영속성 컨텍스트  (0) 2023.06.15
Filter 와 Interceptor  (0) 2023.06.15
OSIV  (0) 2023.06.08
스프링 프레임워크 특징  (0) 2023.06.08

+ Recent posts