问题描述
我正在使用 graphql 和批处理加载器 gems 并遇到此 N+1 查询:
我有一个属于某个帐户的日历约会,当我们显示约会时间时,我们会根据该帐户的时区进行显示。
def appointment_time
read_attribute(:appointment_time).in_time_zone(self.account.timezone)
end
calendarappts {
appointmentTime
}
导致 N+1 查询
POST /graphql
USE eager loading detected
Calendarappt => [:account]
Add to your query: .includes([:account])
Call stack
/....rb:866:in `appointment_time'
/.../app/controllers/graphql_controller.rb:17:in `execute'
我还有许多其他类似的实例方法创建 N+1 查询的示例,但不确定解决此问题的最佳方法。
到目前为止,我刚刚看到了直接克服急切加载关联的方法。我是否需要将每个这样的方法都视为一个关联?
例如,这就是我急切加载帐户本身的方式,当我调用此方法时是否也需要做类似的事情?
field :account,AccountType,null: true,resolve: lambda { |obj,_args,_ctx|
BatchLoader::GraphQL.for(obj.account_id).batch do |account_ids,loader|
Account.where(id: account_ids).each { |account| loader.call(account.id,account) }
end
}
另外,如果我们做这样的事情,它会调用帐户两次吗?
calendarappts {
appointmentTime
account {
id
name
}
}
解决方法
假设您使用 graphql-ruby
来处理您的查询,您应该使用 lookahead
查看需要哪些子字段并相应地准备您的查询。
因此,在您的情况下,在实现 callendarAppts 的方法中,您应该执行以下操作:
field :calendar_appts,...,extras: [:lookahead]
def callendar_appts(lookadead:)
scope = Model.where(...)
if(lookahead.selects?(:appointment_time))
scope = scope.includes([:accounts])
end
scope.all
end
(我在这里吐槽它,因为尚未提供实际实现)