【问题标题】:Eager Loading N+1 issueEager Loading N+1 问题
【发布时间】:2012-06-13 20:11:28
【问题描述】:
 <%- @lessons.includes(:bookmarks).each_with_index do |lesson, index| -%>
          <tr>
            <td class="w6 pl">
              <%- bookmark = lesson.bookmarks.where(user_id: current_user).first -%>
              <%= render :partial => "student/lessons/bookmark", :locals => {:bookmark => bookmark, :lesson => lesson} %>
            </td>
          </tr>
 <%- end -%>

以上代码产生以下 N+1 个查询:

  Bookmark Load (0.3ms)  SELECT "bookmarks".* FROM "bookmarks" WHERE "bookmarks"."lesson_id" IN (1, 2, 3, 4, 5, 6)
  Bookmark Load (0.3ms)  SELECT "bookmarks".* FROM "bookmarks" WHERE "bookmarks"."lesson_id" = 1 AND "bookmarks"."user_id" = 1 LIMIT 1
Rendered student/lessons/_bookmark.html.erb (1.4ms)
  Bookmark Load (0.3ms)  SELECT "bookmarks".* FROM "bookmarks" WHERE "bookmarks"."lesson_id" = 2 AND "bookmarks"."user_id" = 1 LIMIT 1
Rendered student/lessons/_bookmark.html.erb (0.6ms)
  Bookmark Load (0.3ms)  SELECT "bookmarks".* FROM "bookmarks" WHERE "bookmarks"."lesson_id" = 3 AND "bookmarks"."user_id" = 1 LIMIT 1
Rendered student/lessons/_bookmark.html.erb (0.6ms)
  Bookmark Load (0.3ms)  SELECT "bookmarks".* FROM "bookmarks" WHERE "bookmarks"."lesson_id" = 4 AND "bookmarks"."user_id" = 1 LIMIT 1
Rendered student/lessons/_bookmark.html.erb (0.6ms)
  Bookmark Load (0.2ms)  SELECT "bookmarks".* FROM "bookmarks" WHERE "bookmarks"."lesson_id" = 5 AND "bookmarks"."user_id" = 1 LIMIT 1
Rendered student/lessons/_bookmark.html.erb (0.6ms)
  Bookmark Load (0.1ms)  SELECT "bookmarks".* FROM "bookmarks" WHERE "bookmarks"."lesson_id" = 6 AND "bookmarks"."user_id" = 1 LIMIT 1

由于我在循环中使用 where 查询,如何防止第一个查询之后的额外查询?

谢谢!

【问题讨论】:

  • @lessons.includes(:bookmarks).where(bookmarks: {user_id: current_user.id}).each_with_index 然后bookmark = lesson.bookmarks.first?
  • 好的,谢谢!我知道我错过了一些简单的东西。
  • 编辑:实际上这个查询只会返回带有书签的课程。我想返回所有课程,但能够知道课程是否有书签,如果课程有书签,我可以获取书签。
  • 所以你不能在你的情况下使用急切加载。您需要手动执行两个查询

标签: ruby-on-rails ruby-on-rails-3 postgresql eager-loading


【解决方案1】:

您需要手动执行两个查询:

@lessons = Lesson.all # i.e.
@bookmarks = Bookmark.select("bookmarks.*, DISTINCT(lesson_id)").where(user_id: current_user.id)

然后

@lessons.each do |lesson|
  ...
  bookmark = @bookmarks.detect{ |b| b.lesson_id == lesson.id }
  ...
end

【讨论】:

  • 使用 .group(:lesson_id) 时出现 postgres 错误 SELECT "bookmarks".* FROM "bookmarks" WHERE "bookmarks"."user_id" = 1 GROUP BY bookmarks.lesson_id ActiveRecord::StatementInvalid: PGError: ERROR: column "bookmarks.id" 必须出现在 GROUP BY 子句中或在聚合函数中使用
  • 哦,postgre。您可以尝试使用DISTINCT 而不是GROUP BY。我会更新我的答案。而且我不确定它是否适用于 postgre :)
  • @fl00r:RDBMS的名称是PostgreSQL或简称Postgres。不是没有“postgre”这样的东西。
猜你喜欢
  • 2014-05-28
  • 1970-01-01
  • 2019-01-08
  • 2011-09-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-09
相关资源
最近更新 更多