CS Study : N+1 문제의 발생 이유와 해결 방법에 대해 설명해주실 수 있을까요? 해결 방법은 3가지 이상 말씀해주시면 좋습니다.

song yuheon·2023년 10월 19일
0

CS Study

목록 보기
21/50

N+1 문제의 발생 이유

N+1 문제는 데이터베이스 질의와 관련된 성능 문제 중 하나로 관계형 데이터베이스에서 ORM 도구를 사용할 때 주로 발생한다.
이 문제의 핵심은 특정 데이터를 검색할 때 필요한 질의의 수가 예상보다 많아져서 성능 저하가 일어나는 것디다.

예를 들자면 부모 테이블에 있는 각 레코드에 대한 연관된 자식 테이블의 레코드들을 가져오려고 할 때 부모 테이블의 레코드 하나를 가져오는 질의와 그 레코드에 연관된 자식 테이블의 레코드들을 가져오는 별도의 질의가 필요하게 된다.
부모 테이블에 N개의 레코드가 있다면 총 N+1개의 질의가 필요하게 되는데 여기서 N+1 문제의 이름이 유래되었다.

N+1 문제의 해결 방법

  1. 패치 조인 사용
    @Query 어노테이션을 사용하여 JPQL (Java Persistence Query Language)로 쿼리를 작성할 때, JOIN FETCH를 사용하면 관련 엔터티를 함께 가져올 수 있다.
    관련된 테이블 간의 조인을 사용해서 필요한 모든 데이터를 한 번의 질의로 가져올 수 있다.
    이 방법을 사용하면 복잡한 질의가 필요할 수 있지만 질의의 수를 크게 줄일 수 있다.
@Query("SELECT p FROM Book b JOIN FETCH b.apply WHERE b.id = :id")
Parent findByIdWithApply(@Param("id") Long id);
  1. EntityGraph를 사용하는 방법

EntityGraph는 엔터티의 특정 속성을 EAGER 혹은 LAZY로 가져올 것인지를 동적으로 정의할 수 있는 기능이다.
Spring Data JPA에서는 @EntityGraph 어노테이션을 사용하여 쿼리 메서드에 이를 적용할 수 있다.

@EntityGraph(attributePaths = "apply")
List<Book> findAll();
  1. 배치 가져오기
    한 번의 질의로 여러 개의 레코드를 한꺼번에 가져오는 방법이다.
    Hibernate에는 @BatchSize 어노테이션을 제공하여 한 번의 쿼리로 가져올 엔터티의 크기를 설정할 수 있다.
    이는 N+1 문제를 완전히 해결하는 것은 아니지만 질의의 횟수를 줄여 성능을 개선하는 데 도움을 준다.
    예를 들면 부모 테이블의 ID 목록을 이용하여 해당 ID들과 연관된 자식 테이블의 레코드들을 한 번의 질의로 가져올 수 있다.

    • 클래스 위에 설정
      @Entity
      @BatchSize(size = 10)
      public class Parent {
          // ...
      }
    • 설정 파일 application.properties 혹은 application.yml 파일에 적어서 반영
      spring.data.web.pageable.default-page-size=10
      		spring.data.web.pageable.max-page-size=100
  2. 데이터베이스 뷰 사용
    데이터베이스 뷰를 생성하여 필요한 데이터를 미리 조인하거나 집계하는 등의 연산을 수행한 후, 해당 뷰를 조회하여 필요한 데이터를 가져올 수 있다.

profile
backend_Devloper

0개의 댓글