FXFX.GRID

gqlgen 与 Graphql 的那些事

golang
graphql

#什么是 gqlgen

gqlgen 是一个基于 Graphql 这一查询语言实现的 Go 服务端库。特点在于其是依据 GraphqlSchema 为基础,生产与 Schema 对应的 Go 代码。我们只需要对生成的代码进行改写(实现 Resolver)即可。

ResolverGraphql 中的一个概念。

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 // 假设一个作者只有一本书
}

在解析器中主要需要实现 authorsbook 字段。

// 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 问题。

#缓存问题

#资料

FXFX.THEME