ruby 我如何防止n+1问题从数组中产生额外的条件?

lmyy7pcs  于 2023-11-18  发布在  Ruby
关注(0)|答案(2)|浏览(143)

我面临着n+1的问题时,使用条件的数组,来自包括查询。
下面是以下表格:

  1. rems
  2. |id| |name|
  3. 1 aaa
  4. 2 bbb
  5. rem_correlatives
  6. |id| |rem_id| |name| |deleted| |pending_tr|
  7. 1 1 qqqq1 0 0
  8. 2 1 qqqq2 0 1
  9. 3 1 qqqq1 1 0
  10. 4 1 qqqq2 1 1
  11. 5 1 qqqq1 0 0
  12. 6 1 qqqq2 0 1
  13. 7 1 qqqq1 1 0
  14. 8 1 qqqq2 1 1
  15. 9 2 qqqq1 0 0
  16. 10 2 qqqq2 0 1
  17. 11 2 qqqq1 1 0
  18. 12 2 qqqq2 1 1
  19. 13 2 qqqq1 0 0
  20. 14 2 qqqq2 0 1
  21. 15 2 qqqq1 1 0
  22. 16 2 qqqq2 1 1

字符串
以下是模型:

  1. class Rem < ApplicationRecord
  2. has_many :rem_correlatives
  3. end
  4. class RemCorrelative < ApplicationRecord
  5. belongs_to :rem
  6. end


下面是位于/app/controllers/rems_controller.rb的名为rems_controller. rb的控制器

  1. def index
  2. @list_array = Rem.includes(:rem_correlatives).all
  3. end


下面是位于/app/views/rems/index.html.erb的索引视图

  1. <% @list_array.each do |array| %>
  2. <% array.name %>
  3. <% @check_result = array.rem_correlatives.where("deleted=0 AND pending_tr= 1)%>
  4. <% if @check_result.present? %>
  5. No
  6. <% else %>
  7. Yes
  8. <% end %>
  9. <% end %>
  10. <% end%>


x1c 0d1x的数据
我尝试了这个变通代码,它使用列pending_tr=1和deleted=0显示数据数组,但似乎不是一个好的做法。

  1. <% @list_array.each do |array| %>
  2. <% array.name %>
  3. <% array.rem_correlatives.each do |rem_correlative|%>
  4. <!-- Create condition pending_tr=1 AND deleted=0 -->
  5. <% if rem_correlative.pending_tr == 1 && rem_correlative.deleted == 0%>
  6. <% @check_condition = "No" %>
  7. <% else %>
  8. <% @check_condition = "Yes"%>
  9. <% end %>
  10. <% end %>
  11. <!-- Check results from array if the word yes exists -->
  12. <% if @check_condition.include?("Yes") %>
  13. si
  14. <% else %>
  15. no
  16. <% end %>
  17. <% end%>


下面是使用解决方案代码时的后端结果,它的工作和不显示n+1问题。



我如何防止n+1问题从数组生成额外的条件作为良好的代码?

noj0wjuj

noj0wjuj1#

我将在模型中创建一个具有作用域的专用关联。

  1. # in app/models/rem.rb
  2. has_many :pending_rem_correlatives,
  3. class_name: 'RemCorrelative', -> { where(deleted: false, pending_tr: true) }

字符串
然后在控制器和视图中使用这个关联。

  1. # in the controller
  2. @rems = Rem.includes(:pending_rem_correlatives).all
  3. # in the view
  4. <% @rems.each do |rem| %>
  5. <%= rem.name %>
  6. <% if rem.pending_rem_correlatives.any? %>
  7. No such rem correlatives
  8. <% else %>
  9. There are matching rem correlatives
  10. <% end %>
  11. <% end %>

展开查看全部
lbsnaicq

lbsnaicq2#

目前,在您的控制器中,您使用Rem.includes(:rem_correlatives).all来加载Rem记录及其关联的rem_correlatives。但是,当您稍后重新启动@list_array并访问array.rem_correlatives时,它仍然会为每条Rem记录生成额外的查询,从而导致N+1查询问题。
要解决这个问题,您可以使用includes方法预加载必要的关联,并利用查询条件来过滤关联的记录。以下是如何修改控制器代码:

  1. def index
  2. @list_array = Rem.includes(:rem_correlatives)
  3. .where("rem_correlatives.deleted = 0 AND rem_correlatives.pending_tr = 1")
  4. .references(:rem_correlatives)
  5. .all
  6. end

字符串
在您看来,通过此更改,您可以忽略@list_array,而不会对每个Rem记录造成额外的查询:

  1. <% @list_array.each do |array| %>
  2. <%= array.name %>
  3. <% if array.rem_correlatives.present? %>
  4. No
  5. <% else %>
  6. Yes
  7. <% end %>
  8. <% end %>

展开查看全部

相关问题