我有一些困难,解决一个特定的情况,导致性能下降。我很确定这是可以做的事,但我不知道该怎么做。
下面是一个暴露问题的示例模式:
type Answer{
answerId: String!
text: String!
topic: Topic!
}
type Topic {
topicId: String!
name: String!
level: Int!
}extend type Query {
answer(answerId: String!): Answer!
answers: [Answer!]!
}我遵循了文档,特别是我的模式中的这个部分https://gqlgen.com/getting-started/#dont-eagerly-fetch-the-user,它生成以下解析器:
func (r *queryResolver) Answer(ctx context.Context, answerId string) (*models.Answer, error) {
...
#Single Query which retrives single record of Answer from DB.
#Fills a model Answer with the Id and the text
#Proceeds by calling the Topic resolver
...
}
func (r *queryResolver) Answers(ctx context.Context) ([]*models.Answer, error) {
...
#Single Query which retrives list of Answers from DB
#Fills a list of model Answer with the Id and the text
-->#For each element of that list, it calls the Topic resolver
...
}
func (r *answerResolver) Topic(ctx context.Context, obj *models.Answer) (*models.Topic, error) {
...
#Single Query which retrives single record of Topic from DB
#Return a model Topic with id, name and level
...
}当使用answer参数调用answerId查询时,将触发answer解析器,它解析text属性并调用Topic解析器。Topic解析器按预期工作,检索一个Topic,它将其合并到Answer中并返回。
当answers查询在没有answerId参数的情况下被调用时,answer解析器就会被触发,它用一个查询来检索answers列表。然后,对于该列表的每个元素,它调用Topic解析器。Topic检索一个Topic,并将其合并到单个Answer中并返回。
结果在这两种情况下都是可以的,但是如果我想要很多答案的话,answers查询就会成为一个性能问题。对于每个答案,Topic解析器将被触发并执行一个查询,以检索单个记录。
例如。如果我有两个答案->一个查询[Answer0, Answer1],然后一个查询Topic0,一个查询Topic1
例如。10个答案-- [Answer0, ..., Answer9] >1,每个TopicN > 10
我想获得一些topic数组解析器,如
func (r *answersResolver) Topics(ctx context.Context, obj *[]models.Answer) (*[]models.Topic, error) {
...
#Single Query which retrives list of Topics from DB
#Return a list of model Topic with id, name and level
...
}我期望返回数组的每个元素都与Answers数组的对应元素合并。
在某种程度上是可能的吗?我在哪里可以找到这样的方法的例子?谢谢
发布于 2022-04-27 18:35:43
这个问题可以用数据采集器(文档)解决。
我必须为Topics实现以下数据源
package dataloader
import (
"github.com/graph-gophers/dataloader"
)
type ctxKey string
const (
loadersKey = ctxKey("dataloaders")
)
type TopicReader struct {
conn *sql.DB
}
func (t *TopicReader) GetTopics(ctx context.Context, keys dataloader.Keys) []*dataloader.Result {
topicIDs := make([]string, len(keys))
for ix, key := range keys {
topicIDs[ix] = key.String()
}
res := u.db.Exec(
r.Conn,
"SELECT id, name, level
FROM topics
WHERE id IN (?" + strings.Repeat(",?", len(topicIDs-1)) + ")",
topicIDs...,
)
defer res.Close()
output := make([]*dataloader.Result, len(keys))
for index, _ := range keys {
output[index] = &dataloader.Result{Data: res[index], Error: nil}
}
return output
}
type Loaders struct {
TopicLoader *dataloader.Loader
}
func NewLoaders(conn *sql.DB) *Loaders {
topicReader := &TopicReader{conn: conn}
loaders := &Loaders{
TopicLoader: dataloader.NewBatchedLoader(t.GetTopics),
}
return loaders
}
func Middleware(loaders *Loaders, next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
nextCtx := context.WithValue(r.Context(), loadersKey, loaders)
r = r.WithContext(nextCtx)
next.ServeHTTP(w, r)
})
}
func For(ctx context.Context) *Loaders {
return ctx.Value(loadersKey).(*Loaders)
}
func GetTopic(ctx context.Context, topicID string) (*model.Topic, error) {
loaders := For(ctx)
thunk := loaders.TopicLoader.Load(ctx, dataloader.StringKey(topicID))
result, err := thunk()
if err != nil {
return nil, err
}
return result.(*model.Topic), nil
}https://stackoverflow.com/questions/72014642
复制相似问题