Я не понимаю проблему GraphQL N+1
Так что буквально вчера я начал изучать 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 записей обзора из базы данных, а затем для каждого обзора мы делаем еще один вызов базы данных для получения сведений о пользователе. учитывая ID автора.
мы не можем просто удалить Review
из преобразователя и просто сделайте простое СОЕДИНЕНИЕ (если я в sql) в методе get100Reviews
Я не понимаю, почему мы сделали преобразователь обзора, если у нас будет проблема N+1, в то время как мы можем просто сделать простое СОЕДИНЕНИЕ в преобразователе запросов.
Я правильно понимаю GraphQL?
Пожалуйста, пролей сюда свет и расскажи мне.
Спасибо!!
2 ответа
Вы правы - использование соединения позволит вам сделать один запрос к базе данных вместо 101.
Проблема в том, что на практике у вас будет не только одно соединение - ваша модель данных обзора может включать ассоциации с любым количеством других моделей, каждая из которых требует своего собственного предложения соединения. Более того, эти модели могут иметь отношения к другим моделям. Попытка создать единый SQL-запрос, который будет учитывать все возможные запросы GraphQL, становится не только трудным, но и чрезмерно дорогим. Клиент может запросить только обзоры без связанных с ним моделей, но запрос на получение этих обзоров теперь включает 30 дополнительных ненужных представлений. Этот запрос мог занять меньше секунды, но теперь занимает 10.
Учтите также, что отношения между типами могут быть круговыми:
{
reviews {
author {
reviews {
author
}
}
}
}
В этом случае глубина запроса не определена, и невозможно создать один запрос SQL, который бы соответствовал любому возможному запросу GraphQL.
Использование библиотеки, такой как dataloader, позволяет нам решить проблему N+1 за счет пакетной обработки, сохраняя при этом любой отдельный запрос SQL как можно более компактным. Тем не менее, у вас все равно будет несколько запросов. Альтернативный подход - использовать объект GraphQLResolveInfo, переданный преобразователю, чтобы определить, какие поля были запрошены в первую очередь. Затем, если хотите, вы можете сделать только необходимые соединения в своем запросе. Однако разборinfo
объект и построение такого запроса может оказаться непростой задачей, особенно когда вы начинаете иметь дело с глубоко вложенными ассоциациями. С другой стороны,dataloader
это более простое и интуитивно понятное решение.
Я просто написал пакет, который, как мне кажется, может решить N+1 проблем в большинстве случаев на GraphQL на Nodejs. Проверить это!https://github.com/oney/sequelize-proxy
Он в основном использует загрузчики данных для пакетирования нескольких запросов в один, но дополнительно использует функции и определения ассоциаций в sequelize, чтобы сделать его более точным и эффективным.