1

我有两个模型: aPerson有很多Blurb(s).

在控制器中,我正在获取所有人并急切地加载简介:

@people = Person.includes(:blurbs).all.sort { |x, y| y.updated_at <=> x.updated_at }

然后在视图中我遍历@people并显示他们各自的简介计数:

<% @people.each do |person| %>
  <%= person.blurbs.count %>
<% end %>

Rails 的记录器显示确实加载了所有简介:

Blurb Load (0.5ms) SELECT "blurbs".* FROM "blurbs" WHERE "blurbs"."person_id" IN \
(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, \
21, 22, 23, 24, 25, 26, 28, 29, 30, 31, 32, 33, 27, 48, 49, 50)

但随后它在迭代而不是从缓存中获取时再次加载它们:

(0.4ms) SELECT COUNT(*) FROM "blurbs" WHERE "blurbs"."person_id" = $1  [["person_id", 27]]
(0.3ms) SELECT COUNT(*) FROM "blurbs" WHERE "blurbs"."person_id" = $1  [["person_id", 50]]
(0.3ms) SELECT COUNT(*) FROM "blurbs" WHERE "blurbs"."person_id" = $1  [["person_id", 49]]

为了减少 SQL 查询,我缺少什么来使用急切加载的简介?

4

2 回答 2

2

正如您在上面实现的那样,急切加载不会缓存计数。您可能正在寻找防止这些多个“SELECT COUNT...”查询的是 counter_cache。

您可以按如下方式实现它:

class Blurb < ActiveRecord::Base
  belongs_to :person, counter_cache: true
end

…然后在您的 Person 表中添加一个名为blurbs_count

如果您愿意,还可以指定自定义列:

belongs_to :person, counter_cache: :count_of_blurbs

请参阅: http: //guides.rubyonrails.org/association_basics.html了解更多信息。

于 2013-10-31T19:01:30.330 回答
1

对于这种情况,我会考虑counter_cache一些 OTT。试试person.blurbs.size吧。

简而言之,size将有条件地调用lengthcount根据先前的查询。

来自 ActiveRecord 源:

# File activerecord/lib/active_record/relation.rb, line 228
def size
  loaded? ? @records.length : count
end
于 2013-10-31T19:23:09.347 回答