我在解決導致性能下降的特定情況時遇到了一些麻煩。我很確定這是可以做到的,但我不知道該怎么做。
這是暴露問題的示例架構:
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呼叫查詢時,決議器被觸發,它決議屬性并呼叫決議器。決議器按預期作業,檢索它并將其合并到并回傳。answerIdanswertextTopicTopicTopicAnswer
當不帶引數answers呼叫查詢時,決議器被觸發,它使用單個查詢檢索串列。然后,對于該串列的每個元素,它呼叫決議器。 檢索 a并將其合并到單曲中 并回傳。answerIdansweranswersTopicTopicTopicAnswer
結果在這兩種情況下都可以,但是answers如果我要求很多答案,則查詢是性能問題。對于每個答案,Topic決議器都會被觸發并執行查詢以檢索單個記錄。
前任。如果我有 2 個答案 --> 1 個 Query for [Answer0, Answer1],那么 1 個 Query for Topic0和 1 個 forTopic1
前任。10 個答案 --> 1 個[Answer0, ..., Answer9],然后每個 10 個TopicN
我想獲得一些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。
以某種方式可能嗎?我在哪里可以找到這種方法的例子?謝謝
uj5u.com熱心網友回復:
可以使用 Dataloaders ( docs )解決該問題
我必須為以下資料源實作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://www.uj5u.com/shujuku/466891.html
