#什么是 gqlgen
gqlgen
是一个基于 Graphql
这一查询语言实现的 Go 服务端库。特点在于其是依据 Graphql
的 Schema
为基础,生产与 Schema
对应的 Go 代码。我们只需要对生成的代码进行改写(实现 Resolver)即可。
Resolver
是 Graphql
中的一个概念。
Each field on each type is backed by a function called the resolver which is provided by the GraphQL server developer.
每个类型中的每个字段都被一个函数所支持,这个函数就叫做 resolver,即解析器,这个函数是由后端开发者所提供(实现)的。
#对配置文件的扩展阅读
#N + 1 问题
试想有以下数据结构
// scheme
type Query {
authors: [Author]
}
type Book {
id: Int
title: String
}
type Author {
id: Int
name: String
book: Book // 假设一个作者只有一本书
}
在解析器中主要需要实现 authors
和 book
字段。
// resolvers
{
"Query":{
authors:()=>{ //实现 authors 字段
return db.getAuthors()
}
},
"Author":{
book:(authorId)=>{ // 处理 books 字段
return db.getBook(authorId)
}
}
}
请求 authors
时,GraphQL 将发出一条 SQL 查询全部作者,然后在处理每个作者的书籍字段时,它会为每个作者单独发出一条 SQL 查询。假设有 100 个作者,那最终将总计 101 条 SQL 请求(1 条查询所有的作者,以及 100 条查询书籍)。显然这非常的不合理。而问题的根源就是在 Author 的 Resolver 中。
在 sf 中有一问 I don't understand the GraphQL N+1 problem ,其指出可以移除 Author 的解析器,然后在 Query 中直接使用 SQL 的 JOIN 语句,这样就能解决 N+1 问题了。
// resolvers
{
"Query":{
authors:()=>{ //实现 authors 字段
return db.getAuthors() // 方法内直接实现 books 查询!
}
},
}
这固然解决了 N+1 问题,但似乎破坏了 GraphQL 的原则 -- 只加载必要的字段。使用 GraphQL 的一大优势就是我们可以自由的查询所需字段,GraphQL 根据查询自己决定是否去执行对应的解析器。而这种解决方案使得无论我们是否挑选字段 book
,JOIN 语句都会执行。这会使得原先只需 1s 的查询变成 10s,甚至更多。另外,问题远不止于次,在实际应用中,我们的数据模型会更加的复杂,这使得几乎无法写出一个完美的解析器去覆盖所有的查询情况。
#解决方案
使用 dataloader 解决 N+1 问题。
#缓存问题
#资料
- Graphq: https://graphql.org/
- gqlgen: https://gqlgen.com/