Rails "includes" 方法和避免N+1查询
Rails "includes" Method and Avoiding N+1 Query
我对 Rails includes
方法的理解并不如我所愿,我 运行 遇到了一个我希望澄清的问题。我有一个 Board 模型 has_many :members
和 has_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)
以完成查询。
我对 Rails includes
方法的理解并不如我所愿,我 运行 遇到了一个我希望澄清的问题。我有一个 Board 模型 has_many :members
和 has_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)
以完成查询。