Rails "includes" 方法和避免N+1查询

Rails "includes" Method and Avoiding N+1 Query

我对 Rails includes 方法的理解并不如我所愿,我 运行 遇到了一个我希望澄清的问题。我有一个 Board 模型 has_many :membershas_many :lists(以及一个列表 has_many :cards)。在以下 boards controller 中,show 方法如下所示:

def show
  @board = Board.includes(:members, lists: :cards).find(params[:id])
  ...
end

为什么这里需要includes方法?为什么我们不能只使用 @board = Board.find(params[:id]) 然后通过 @board.members@board.lists 访问成员和列表?我想我真的不明白为什么我们需要预取。如果有人可以详细说明为什么这在 SQL 查询方面更有效,那就太棒了。谢谢!

根据 Rails 文档:

Eager loading is the mechanism for loading the associated records of the objects returned by Model.find using as few queries as possible.

当您简单地加载一条记录并稍后查询它的不同关系时,您每次都必须 运行 一个查询。以这个例子为例,同样来自 Rails 文档:

clients = Client.limit(10)

clients.each do |client|
  puts client.address.postcode
end

这段代码执行了 11 次数据库调用来做一些非常微不足道的事情,因为它必须进行每次查找,一次一个。

将上面的代码与此示例进行比较:

clients = Client.includes(:address).limit(10)

clients.each do |client|
  puts client.address.postcode
end 

这段代码执行了 2 次数据库调用,因为所有必要的关联都在一开始就包含了。

Here's a link to the pertinent section of the Rails docs.

额外

最近要注意的一点:如果您使用关联模型进行更复杂的查询,例如:

Board.includes(:members, lists: :cards).where('members.color = ?', 'foo').references(:members)

您需要确保包含附加的 references(:used_eager_loaded_class) 以完成查询。