【问题标题】:check_box_tag includes n+1 querycheck_box_tag 包含 n+1 个查询
【发布时间】:2018-01-06 18:34:35
【问题描述】:

文章所属故事列表中的以下行(在编辑文章页面上,允许我将文章分配给故事)有效,但会产生 n+1 查询(我认为)。

导致问题的位是@article.stories.include?(s),它会检查一篇文章是否已经属于一个故事:

<%= check_box_tag "article[story_ids][]", s.id, @article.stories.include?(s) %>

日志说 Rails 正在执行 50 多个查询(所有故事),因为这一点;示例中的 article_id = 266:

Story Exists (0.4ms)  SELECT  1 AS one FROM "stories" INNER JOIN "articles_stories" ON "stories"."id" = "articles_stories"."story_id" WHERE "articles_stories"."article_id" = $1 AND "stories"."id" = $2 LIMIT 1  [["article_id", 266], ["id", 6]]
Story Exists (0.3ms)  SELECT  1 AS one FROM "stories" INNER JOIN "articles_stories" ON "stories"."id" = "articles_stories"."story_id" WHERE "articles_stories"."article_id" = $1 AND "stories"."id" = $2 LIMIT 1  [["article_id", 266], ["id", 51]]
Story Exists (0.3ms)  SELECT  1 AS one FROM "stories" INNER JOIN "articles_stories" ON "stories"."id" = "articles_stories"."story_id" WHERE "articles_stories"."article_id" = $1 AND "stories"."id" = $2 LIMIT 1  [["article_id", 266], ["id", 41]]
Etc., etc.

article_id = 266 实际属于的故事数是……2:

 select * from articles_stories where article_id = 266;

 article_id | story_id 
 ------------+----------
    266 |       35
    266 |        5

 (2 rows)

我该如何解决?

更新:数据库、整个块和控制器

Article.rb:

has_and_belongs_to_many :stories

故事.rb:

has_and_belongs_to_many :articles

check_box_tag 所在的整个代码块(按类别打印您可以分配给文章的故事列表)是:

<% @stories.group_by(&:category).sort_by{|c, stories| c.category}.each do |c, stories| %>
  <div class="admin-stories-in-categories">
    <strong><%= c.category unless c.nil? %></strong>
      <ul>
        <% for s in stories %>
          <li>
            <%= check_box_tag "article[story_ids][]", s.id, @article.stories.include?(s) %>
            <%= s.story %>
          </li>
        <% end %>
      </ul>
  </div>
<% end %>

在articles_controller.rb中:

@stories = Story.all.includes(:category).order(:story)

回答:

以下 AbM 的回答使 N+1 个查询消失,而是返回一个查询:

Returns `(0.8ms)  SELECT "stories"."id" FROM "stories" INNER JOIN "articles_stories" ON "stories"."id" = "articles_stories"."story_id" WHERE "articles_stories"."article_id" = $1  [["article_id", 266]]`

【问题讨论】:

  • 修复n+1查询有很多问题和技巧,你试过了吗?
  • 我有。他们没有工作,因此问题。你删掉了“新年快乐”?
  • 为什么不起作用?您能否更清楚地说明什么是行不通的,您尝试过什么?

标签: sql ruby-on-rails ruby


【解决方案1】:

感谢,因为活动记录关系上的 include? 方法在 sql 中执行 EXIST 操作,如果关系未加载,如图所示 here

尝试将文章故事存储在变量中:

<% article_stories_ids = @article.stories.pluck(:id) %>
<% @stories.group_by(&:category).sort_by{|c, stories| c.category}.each do |c, stories| %>
  <div class="admin-stories-in-categories">
    <strong><%= c.category unless c.nil? %></strong>
      <ul>
        <% stories.each do |s| %>
          <li>
            <%= check_box_tag "article[story_ids][]", s.id, article_stories_ids.include?(s.id) %>
            <%= s.story %>
          </li>
        <% end %>
      </ul>
  </div>
<% end %>

【讨论】:

  • 请不要在 ruby​​ 中使用for 循环
  • 我只是将他们的示例用于现有循环。修改只是为了将 id 存储在变量中
  • 好的,谢谢@AbM,这行得通。将发布它返回的内容。
  • 为什么不@Зелёный?有什么选择?
【解决方案2】:

我们需要您的数据库架构和您在控制器中使用的查询(如果有的话)——但您可能只需要执行Article.includes(:stories).find(params[:id]) 之类的操作

我建议将 Bullet 之类的东西插入到您的开发堆栈中。

https://github.com/flyerhzm/bullet

【讨论】:

  • 我添加了关系和控制器位。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-21
  • 1970-01-01
  • 1970-01-01
  • 2019-01-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多