Graphql에서의 N+1 Query문제와 Dataloader

이정훈·2025년 2월 4일

GraphQL

목록 보기
13/13

N + 1 Query문제

N+1 Query문제란?

N+1 문제는 연관 관계에서 필요 이상의 쿼리를 수행하는 비효율적인 상황을 말한다.

예를 들어 데이터베이스에서 스승 테이블과 학생 테이블이 존재하고 스승과 학생은 1:N 연관 관계를 가지고 있다고 가정해보자.

학생 중에 A 또는 B 또는 C를 스승으로 두는 학생을 찾으려고 한다.

쉽게 생각할 수 있는 방법은 아래와 같다.
1. A를 스승으로 둔 학생을 찾는다.
2. B를 스승으로 둔 학생을 찾는다.
3. C를 스승으로 둔 학생을 찾는다.
총 3번의 쿼리를 통해 위 상황의 해결방법을 구했다.
즉, 서버와 데이터베이스가 총 3번의 교신이 이뤄져야 했다.
당장 3번의 교신은 괜찮은 것처럼보이지만 매우 많은 스승에 대해서 학생을 찾으려고 한다면 더 많은 교신이 이루어져야 할 것이다.
이렇게 많은 교신은 오버헤드로 적용되어 성능에 영향을 미칠 수 있다.

이를 생각하고 나아진 해결 방법을 찾는다면 아래와 같다.
1. A 또는 B 또는 C를 스승으로 둔 학생을 찾는다.
1번의 쿼리만으로 위 상황을 해결했다.
실제로 데이터베이스에서 위와 같은 쿼리를 지원하기 때문에 말장난이 아니다.

요약

N+1 Query 문제는 불필요하게 쿼리를 추가적으로 함으로써 비효율적이 되는 상황을 말하는것이다.

Graphql에서 N + 1 Query

HTTP를 통한 API에서는 N + 1 Query가 큰 문제가 되지 않는다.
HTTP기반 API에서는 필요한 데이터보다 많은 데이터를 가져오는 over fetching이 더 문제가 된다.
이에 대해서는 자세히 설명하지 않겠다.

반면, Graphql에서는 over fetching보다 N + 1 Query가 큰 문제가 됩니다.
GraphQL에서는 요청하는 데이터가 중첩된 형태로 구성되기 때문입니다.
예를 들어, 사용자의 정보를 가져오는 쿼리에서 사용자의 주소나 댓글 목록과 같은 추가적인 데이터도 함께 요청할 수 있습니다.
이러한 요청을 처리할 때, 각 필드마다 리졸버(Resolver)를 통해 데이터를 해결해야 하므로, 복잡한 관계를 가진 데이터 구조에서는 N+1 Query 문제가 발생할 가능성이 큽니다.
즉, GraphQL에서 ObjectType이 중첩된 형태를 가지면, 하나의 쿼리에서 여러 리졸버가 연쇄적으로 호출해 N + 1 Query 문제가 생길 수 있습니다.

예를 들어, 아래와 같은 쿼리가 있다고 가정해 봅시다:

query {
  users {
    id
    name
    address {
      street
      city
    }
  }
}

이 경우, users를 조회하는 리졸버에서 사용자의 기본 정보를 가져온 뒤, 각 사용자마다 주소(address)를 조회해야 합니다. 그런데 주소를 조회할 때마다 별도의 쿼리가 실행된다면, 사용자가 많아질수록 쿼리 횟수가 급격히 늘어날 수 있습니다. 예를 들어, 사용자가 100명이라면, 1번의 쿼리로 모든 사용자 데이터를 가져온 뒤, 각각의 사용자에 대해 100번의 주소 조회 쿼리가 실행됩니다. 이는 N+1 Query 문제로 이어집니다.

DataLoader

DataLoader는 애플리케이션에서 data fetching 레이어에서 사용되는 기능입니다.
이를 통해 데이터베이스나 웹 서비스에서 간단하고 일관적인 batch 기능과 cache기능을 사용할 수 있습니다.
특히 Graphql에서 많이 쓰이는데 batch 기능을 통해 N + 1 Query 문제를 해결할 수 있기 때문입니다.

profile
기록으로 흔적을 남깁니다.

0개의 댓글