express - 我不明白 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
从解析器中删除并在 get100Reviews 方法中进行简单的 JOIN(如果我在 sql 中)
如果我们遇到 N+1 问题,我不明白为什么我们要做 Review 解析器,而我们可以在 Query 解析器中进行简单的 JOIN。
我理解 GraphQL 对吗?
请有人在这里阐明一下,并告诉我。
谢谢 !!
解决方案
你是对的——使用连接可以让你进行单个数据库查询而不是 101。
问题在于,在实践中,您不会只有一个连接——您的评论数据模型可能包括与任意数量的其他模型的关联,每个模型都需要自己的连接子句。不仅如此,这些模型可能与其他模型本身有关系。尝试创建一个 SQL 查询来处理所有可能的 GraphQL 查询不仅困难,而且成本高得令人望而却步。客户可能只请求没有关联模型的评论,但获取这些评论的查询现在包括 30 个额外的、不必要的视图。该查询可能花费了不到一秒的时间,但现在需要 10 秒。
还要考虑类型之间的关系可以是循环的:
{
reviews {
author {
reviews {
author
}
}
}
}
在这种情况下,查询的深度是不确定的,并且不可能创建一个可以容纳任何可能的 GraphQL 查询的 SQL 查询。
使用像dataloader这样的库可以让我们通过批处理来缓解 N+1 问题,同时保持任何单个 SQL 查询尽可能精简。也就是说,您仍然会遇到多个查询。另一种方法是利用传递给解析器的 GraphQLResolveInfo 对象来确定首先请求了哪些字段。然后,如果您愿意,您可以只在查询中进行必要的联接。但是,解析info
对象并构造此类查询可能是一项艰巨的任务,尤其是当您开始处理深度嵌套的关联时。另一方面,dataloader
是一种更简单直观的解决方案。
推荐阅读
- javascript - 如何在Javascript中检查字符串结束位置是否存在值?
- python - 可以使用色调参数在 Seaborn 关节网格中获得 lmplot 吗?
- php - 当它有外键时不再保存值,但是当我删除外键约束时,它确实保存了。可能是什么问题呢?
- html - 严格当它包含包含在列中的项目时,其内容的宽度
- reactjs - React / Recoil - setAtom 新值何时可用?
- javascript - 如何将像素值数组(灰度)转换为节点中的图像?
- python - 按字母表对表示卡片的元组列表进行排序,然后排名
- c# - HttpClient post call 适用于邮递员,但不适用于 C#
- java - Apache Tomcat 在 localhost:8080 显示一个已经制作的 WAR 文件而不是主页
- javascript - 如何使用 javascript 关闭浏览器开发控制台?