Я не понимаю проблему GraphQL N + 1 - PullRequest
0 голосов
/ 24 марта 2020

Итак, только вчера я начал изучать graphql, это действительно интересно, и довольно легко выучить и понять на самом деле. я начал читать некоторые статьи и обнаружил проблему N + 1. я нашел этот пример здесь

Запрос

# getting the top 100 reviews
{
  top100Reviews {
    body
    author {
      name
    }
  }
}

Схема


const typeDefs = gql`
  type User {
    id: ID!
    name: String
  }
  type Review {
    id: ID!
    body: String
    author: User
    product: Product
  }
  type Query {
    top100Reviews: [Review]
  }
`;

и, наконец, решатели

const resolver = {
  Query: {
    top100Reviews: () => get100Reviews(),
  },
  Review: {
    author: (review) => getUser(review.authorId),
  },
};

в этой статье он сказал

Когда мы выполним следующий запрос, чтобы получить первые 100 отзывов и соответствующие имена авторов, мы сначала сделаем один вызов чтобы получить 100 записей рецензий из базы данных, а затем для каждого рецензирования мы делаем еще один вызов в базу данных, чтобы получить данные о пользователях с указанием идентификатора автора.

не можем просто удалить Review из преобразователя и просто сделайте простое JOIN (если я в sql) в методе get100Reviews

я не понимаю, почему мы сделали преобразователь Review, если у нас возникнет проблема N + 1 мы можем просто сделать простое ПРИСОЕДИНЕНИЕ в решателе запросов.

Правильно ли я понимаю GraphQL?

Пожалуйста, кто-нибудь пролил немного света сюда и скажите мне. !

1 Ответ

0 голосов
/ 24 марта 2020

Вы правы - использование объединения позволит вам сделать один запрос к базе данных вместо 101.

Проблема в том, что на практике у вас не было бы просто одного объединения - ваша модель данных обзора может включать ассоциации с любым количеством других моделей, каждая из которых требует своего собственного предложения соединения. Не только это, но эти модели могут иметь отношения к другим моделям сами. Попытка создать один запрос SQL, который будет учитывать все возможные запросы GraphQL, становится не только сложной, но и чрезмерно дорогой. Клиент может запрашивать только обзоры, не имеющие ни одной из связанных моделей, но запрос для получения этих обзоров теперь включает в себя 30 дополнительных ненужных представлений. Этот запрос мог занять меньше секунды, но теперь занимает 10.

Также учтите, что отношения между типами могут быть круговыми:

{
  reviews {
    author {
      reviews {
        author
      }
    }
  }
}

В этом случае глубина запроса не определена невозможно создать один запрос SQL, который бы удовлетворил любой возможный запрос GraphQL.

Использование библиотеки, такой как dataloader , позволяет нам уменьшить N + 1 проблема, связанная с пакетной обработкой, при этом любой отдельный запрос SQL должен быть максимально скудным. Тем не менее, вы все равно будете в конечном итоге с несколькими запросами. Альтернативный подход заключается в использовании объекта GraphQLResolveInfo, переданного резолверу, чтобы определить, какие поля были запрошены в первую очередь. Тогда, если хотите, вы можете делать только необходимые объединения в своем запросе. Однако анализ объекта info и построение такого рода запросов может оказаться сложной задачей, особенно после того, как вы начнете работать с глубоко вложенными ассоциациями. С другой стороны, dataloader является более простым и интуитивно понятным решением.

...