提问人:Carlos Morales 提问时间:11/17/2023 最后编辑:user3402754Carlos Morales 更新时间:11/17/2023 访问量:57
如何防止生成额外条件的数组出现 n+1 问题?
How can I prevent n+1 issue from array that is generating additional conditions?
问:
在来自包含查询的数组上使用条件时,我遇到了 n+1 问题。
下表如下:
rems
|id| |name|
1 aaa
2 bbb
rem_correlatives
|id| |rem_id| |name| |deleted| |pending_tr|
1 1 qqqq1 0 0
2 1 qqqq2 0 1
3 1 qqqq1 1 0
4 1 qqqq2 1 1
5 1 qqqq1 0 0
6 1 qqqq2 0 1
7 1 qqqq1 1 0
8 1 qqqq2 1 1
9 2 qqqq1 0 0
10 2 qqqq2 0 1
11 2 qqqq1 1 0
12 2 qqqq2 1 1
13 2 qqqq1 0 0
14 2 qqqq2 0 1
15 2 qqqq1 1 0
16 2 qqqq2 1 1
以下是模型:
class Rem < ApplicationRecord
has_many :rem_correlatives
end
class RemCorrelative < ApplicationRecord
belongs_to :rem
end
这是位于 /app/controllers/rems_controller.rb 的名为 rems_controller.rb 的控制器
def index
@list_array = Rem.includes(:rem_correlatives).all
end
下面是位置 /app/views/rems/index.html.erb 的索引视图
<% @list_array.each do |array| %>
<% array.name %>
<% @check_result = array.rem_correlatives.where("deleted=0 AND pending_tr= 1)%>
<% if @check_result.present? %>
No
<% else %>
Yes
<% end %>
<% end %>
<% end%>
我尝试了使用列 pending_tr=1 和 deleted=0 显示数据数组的解决方法代码,但似乎不是一个好做法。
<% @list_array.each do |array| %>
<% array.name %>
<% array.rem_correlatives.each do |rem_correlative|%>
<!-- Create condition pending_tr=1 AND deleted=0 -->
<% if rem_correlative.pending_tr == 1 && rem_correlative.deleted == 0%>
<% @check_condition = "No" %>
<% else %>
<% @check_condition = "Yes"%>
<% end %>
<% end %>
<!-- Check results from array if the word yes exists -->
<% if @check_condition.include?("Yes") %>
si
<% else %>
no
<% end %>
<% end%>
这是使用解决方法代码时的后端结果,它有效且不显示 n+1 问题。
如何防止数组生成其他条件作为良好代码的 n+1 问题?
答:
1赞
spickermann
11/17/2023
#1
我将创建与模型中的范围的专用关联。
# in app/models/rem.rb
has_many :pending_rem_correlatives,
class_name: 'RemCorrelative', -> { where(deleted: false, pending_tr: true) }
然后将在控制器和视图中使用此关联。
# in the controller
@rems = Rem.includes(:pending_rem_correlatives).all
# in the view
<% @rems.each do |rem| %>
<%= rem.name %>
<% if rem.pending_rem_correlatives.any? %>
No such rem correlatives
<% else %>
There are matching rem correlatives
<% end %>
<% end %>
评论
0赞
Carlos Morales
11/17/2023
嗨,斯皮克曼,我尝试了你的代码,它仍在生成 n+1
0赞
spickermann
11/17/2023
当您仍然有子查询时,很可能是因为您在上面的评论中提到的视图中的其他子条件。你介意分享你的实际代码,还是至少分享一个更接近现实的例子?
1赞
user3402754
11/17/2023
#2
目前,在控制器中,您正在使用 Rem 记录及其关联的 .但是,当您稍后迭代和访问 时,它仍然会为每个 Rem 记录生成额外的查询,从而导致 N+1 查询问题。Rem.includes(:rem_correlatives).all
rem_correlatives
@list_array
array.rem_correlatives
为了解决这个问题,您可以使用 includes 方法预加载必要的关联,还可以利用查询条件来筛选关联的记录。以下是修改控制器代码的方法:
def index
@list_array = Rem.includes(:rem_correlatives)
.where("rem_correlatives.deleted = 0 AND rem_correlatives.pending_tr = 1")
.references(:rem_correlatives)
.all
end
通过此更改,在您看来,您可以循环访问@list_array而不会对每个 Rem 记录产生额外的查询:
<% @list_array.each do |array| %>
<%= array.name %>
<% if array.rem_correlatives.present? %>
No
<% else %>
Yes
<% end %>
<% end %>
评论
0赞
Carlos Morales
11/17/2023
我正在尝试使用子条件,并且不想触摸控制器,因为我在视图上有其他子条件。
评论