1

私は 2 つのモデルを持っています: aPersonには many があり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代わりに試してください。

つまり、前のクエリに応じて条件付きでorsizeを呼び出します。lengthcount

ActiveRecord ソースから:

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