Graphql Ruby N + 1 查询因为方法调用另一个关系

问题描述

我正在使用 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

(我在这里吐槽它,因为尚未提供实际实现)

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...