当您执行深度嵌套的 GraphQL 查询时,会调用多少 SQL 次数据库?
How many SQL database calls are made when you do a deeply nested GraphQL query?
我知道您要使用 GraphQL 为查询实现 backend handlers。所以如果你使用的是 PostgreSQL,你可能会有这样的查询:
query {
authors {
id
name
posts {
id
title
comments {
id
body
author {
id
name
}
}
}
}
}
天真的解决方案是做这样的事情:
const resolvers = {
Query: {
authors: () => {
// somewhat realistic sql pseudocode
return knex('authors').select('*')
},
},
Author: {
posts: (author) => {
return knex('posts').where('author_id', author.id)
},
},
Post: {
comments: (post) => {
return knex('comments').where('post_id', post.id)
},
},
};
然而,这将是一个相当大的问题。它基本上会执行以下操作:
- 对所有作者进行 1 次查询。
- 对于每个作者,查询所有 posts。 (n + 1 个查询)
- 对于每个 post,查询所有评论。 (n + 1 个查询)
所以这就像一个扇形查询。如果有 20 个作者,每个作者有 20 个 posts,那将是 21 个数据库调用。如果每个 post 有 20 条评论,那将是 401 次数据库调用! 20 位作者解决了 400 posts,这解决了 8000 条评论,这并不是你真正会这样做的方式,而是为了证明这一点。 1 -> 20 -> 400 个分贝调用。
如果我们添加 comments.author
次调用,那就是另外 8000 次数据库调用(每个评论一次)!
你如何将其批量化为 3 个数据库调用(每种类型 1 个)?这就是优化的 GraphQL 查询解析器本质上所做的吗?或者对于这种情况最好的办法是什么?
这是 GraphQL N+1 加载问题。
基本上有两种方法可以解决(为简单起见,假设它只需要加载作者及其 posts)
使用Dataloader模式。基本上它的想法是将每个作者的 posts 的实际加载时间推迟到特定时间,以便 N 个作者的 posts 可以由单个 SQL 一起批量加载.它还提供了缓存功能,以进一步提高同一请求的性能。
使用“前瞻模式”(here 中描述了一个 Java 示例)。基本上它的想法是,在解析 authors 时,您只需向前看查询是否在子字段中包含 posts。如果是,则您可以使用 SQL 联接将作者及其 post 集中在单个 SQL.
中
此外,为了防止恶意客户端发出检索非常大的图的请求,一些 GraphQL 服务器将分析查询并对其施加 depth limit。
我知道您要使用 GraphQL 为查询实现 backend handlers。所以如果你使用的是 PostgreSQL,你可能会有这样的查询:
query {
authors {
id
name
posts {
id
title
comments {
id
body
author {
id
name
}
}
}
}
}
天真的解决方案是做这样的事情:
const resolvers = {
Query: {
authors: () => {
// somewhat realistic sql pseudocode
return knex('authors').select('*')
},
},
Author: {
posts: (author) => {
return knex('posts').where('author_id', author.id)
},
},
Post: {
comments: (post) => {
return knex('comments').where('post_id', post.id)
},
},
};
然而,这将是一个相当大的问题。它基本上会执行以下操作:
- 对所有作者进行 1 次查询。
- 对于每个作者,查询所有 posts。 (n + 1 个查询)
- 对于每个 post,查询所有评论。 (n + 1 个查询)
所以这就像一个扇形查询。如果有 20 个作者,每个作者有 20 个 posts,那将是 21 个数据库调用。如果每个 post 有 20 条评论,那将是 401 次数据库调用! 20 位作者解决了 400 posts,这解决了 8000 条评论,这并不是你真正会这样做的方式,而是为了证明这一点。 1 -> 20 -> 400 个分贝调用。
如果我们添加 comments.author
次调用,那就是另外 8000 次数据库调用(每个评论一次)!
你如何将其批量化为 3 个数据库调用(每种类型 1 个)?这就是优化的 GraphQL 查询解析器本质上所做的吗?或者对于这种情况最好的办法是什么?
这是 GraphQL N+1 加载问题。
基本上有两种方法可以解决(为简单起见,假设它只需要加载作者及其 posts)
使用Dataloader模式。基本上它的想法是将每个作者的 posts 的实际加载时间推迟到特定时间,以便 N 个作者的 posts 可以由单个 SQL 一起批量加载.它还提供了缓存功能,以进一步提高同一请求的性能。
使用“前瞻模式”(here 中描述了一个 Java 示例)。基本上它的想法是,在解析 authors 时,您只需向前看查询是否在子字段中包含 posts。如果是,则您可以使用 SQL 联接将作者及其 post 集中在单个 SQL.
中
此外,为了防止恶意客户端发出检索非常大的图的请求,一些 GraphQL 服务器将分析查询并对其施加 depth limit。