본문 바로가기

백엔드

N+1문제

N+1문제를 위해 필요한 기본 개념들에 대해 먼저 설명하겠습니다

ORM(Object-Relatonal Mapping) 우리가 일반 적으로 알고 있는 애플리케이션 Class와 RDB(Relational DataBase)의 테이블을 매핑(연결)한다는 뜻이며, 기술적으로는 어플리케이션의 객체를 RDB 테이블에 자동으로 영속화 해주는 것이라고 보면됩니다

장점

  1. SQL이 아닌 Method를 이용하여 DB조작할 수 있어, 비지니스 로직을 구성하는데만 집중할 수 있습니다
  2. 객체지향적인 코드 작성 가능 -> 생산성 증가로 이어집니다
  3. DB 종류를 변경할 경우에 ORM을 사용하면 쿼리를 수정할 필요가 없습니다

JPA

  • • JAVA에서 ORM 기술 표준으로 사용하는 인터페이스 모음입니다
  • • 자바에서 관계형 데이터베이스를 사용하는 방식을 정의한 인터페이스입니다

JPA를 사용하는 이유

  • 반복적인 CRUD SQL을 처리해줍니다
  • SQL이 아닌 객체 중심으로 개발할 수 있습니다
  • 데이터베이스는 객체의 상속관계를 지원하지 않지만 JPA는 이를 가능하게 해줍니다.

이제 본격적으로 N+1문제에 대해 이야기해보도록 하겠습니다.

N+1문제

  • N+1문제는 연관관계를 가지는 엔티티들 중에서 연관 관계에서 발생하는 이슈입니다

A라는 엔티티(N)가 B라는 엔티티(1)와 연관관계를 가지고 있다고 해보겠습니다. 우리가 A라는 엔티티를 조회할 때, B라는 엔티티에 대한 데이터를 조회하기 위해 B라는 데이터의 개수(N)만큼 조회 쿼리가 추가로 발생하는 것을 N+1문제라고 합니다

예시로 현재 제가 혼자 개발 중인 웹사이트 프로젝트를 기반으로 N+1문제에 대해 알아보겠습니다.

설명) 학생 → 게시물(하위 엔티티) 1:N관계

Post엔티티

 

 

Member엔티티

 

 

테스트코드

 

 

 

멤버의 포스트를 가져오는 과정에서 N+1문제 발생합니다.

이 부분은 모든 회원 정보를 DB에서 불러오는 쿼리입니다.

 

그러나 이 회원정보를 가져온 후에 회원마다 추가적인 쿼리가 실행되고 있습니다.

 

 

 

 

 

 

 

여기서 문제점은 회원 하나당 하나의 쿼리가 추가로 실행되고 있다는 점입니다. 이러면 N+1개의 쿼리가 추가로 실행되어야 합니다.

쉽게 말하면 첫 select 쿼리에서 모든 회원 정보가 가져와진다. 그런데 각 회원에 대한 상세정보를 또 한번씩. 즉 N번 조회한다는 것입니다.

이로 인해 발생하는 문제점은 ?

  • 성능저하 -> 불필요한 쿼리가 여러번 실행되기 때문입니다.
  • 데이터베이스 부하
  • 네트워크 비용 증가
  • 어플리케이션 응답 시간 증가
  • 메모리 부하

등이 있습니다.

이를 해결하기 위한 방법으로 몇가지가 있습니다

  • FetchType
  • 연관 관계가 있는 엔티티까지 끌어올지에 대한 여부를 결정할 수 있습니다. LAZY로 설정하면 children을 실제 엔티티에서 끌어오지 않고 프록시를 받아옵니다 그렇기에 실제 호출 때는 단순 프록시를 넣어놓고 실제 children에 있는 객체를 끌어올 필요가 없습니다 하지만 전체를 조회하는 상황에서는 또한 전체를 조회하기 때문에 근본적인 해결책이 될 수 없습니다
  • @EntityGraph

이는 연관 관계를 가진 객체를 한번에 끌어올 수 있는 기능을 제공하는데, attributePaths에 쿼리 수행 시 바로 끌어올 필드명을 지정하면 바로 가져올 수 있습니다.

느낀점

스프링 공부를 시작한 지 한달밖에 되지 않아, 코드의 효율성이나 눈에 보이지 않는 부분에 대해서 생각해본 적이 없는데, N+1문제에 대해 다뤄보며 효율성 측면에서도 생각할 수 있는 계기가 된 것 같습니다.

향후계획

곧 혼자 진행중인 웹페이지 제작 프로젝트에 게시글 Board 및 댓글 기능을 구현할 예정이었는데, Post의 댓글 조회 시 N+1문제가 발생하지 않도록 @EntityGraph를 사용해볼 예정입니다. 실행 완료 시 후기글까지 올려보도록 하겠습니다.

'백엔드' 카테고리의 다른 글

DB replication  (0) 2023.09.02
Swagger을 통해 OpenAPI 문서화하기  (0) 2023.08.24