1

Following.rb

belongs_to :show

def cached_show
  Rails.cache.fetch([self, :show]) do
    show      
  end
end

View:

<% @recently_favorited.each do |following| %>
<li>
  <%= link_to "#{following.cached_show.name}", show_path(:permalink => following.cached_show.permalink) %> <span><%= "(#{pluralize(following.cached_show.followers, "follower")})" %></span>
</li>
<% end %>

Result in the console:

Cache read: followings/632770-20120929132253/show
Cache generate: followings/632770-20120929132253/show
  Show Load (0.7ms) SELECT `shows`.* FROM `shows`WHERE `shows`.`id` = 617 LIMIT 1
Cache write: followings/632770-20120929132253/show

Cache read: followings/632770-20120929132253/show
Cache fetch_hit: followings/632770-20120929132253/show

Cache read: followings/632770-20120929132253/show
Cache fetch_hit: followings/632770-20120929132253/show

Question:
Is this even a "correct" implementation of fetching/caching an association?
And what about performance?
In some views (as in the example) it will hit the cache 3 times per loop. In my case I'm looping 10 items in the footer, so it will make 30 hits on every request. Is this fine, or will a single n+1 query per loop be better?

Advise and general best practices appreciated :)

4

2 に答える 2

2

キャッシュをヒットするための明確なメソッドを作成することと、キャッシュをフレッシュにすることは、私が言えることからは一般的ではありません。

キャッシュキーにオブジェクトを含めると、フィールドがキーの作成に使用されるため、ほとんどのcache場合、常に要求するメソッドを呼び出すだけです。updated_at

Following今のあなたの例では、奇妙な部分は、モデルの関連付けにアクセスする以外は、実際には何もしないということです。したがって、Showモデルを直接クエリする必要があります。

@recently_favorited_shows = Show.joins(:followings).order("followings.created_at DESC").uniq

次に、ビューで、ショーをループします。クエリは1つだけで、n+1はありません

何千ものヒットが予想される場合は、結果をキャッシュし@recently_favorited_showsてX分ごとに期限切れにすることをお勧めします。

@recently_favorited_shows = cache_store.fetch('recently_favorited_shows', expires_in: 5.minutes){Show.joins(:followings).order("followings.created_at DESC").uniq}

別の注意点として、しばらくの間それを実行したい場合は、ビュー側でのキャッシュ使用量に関する適切な記述があります:http: //37signals.com/svn/posts/3113-how-key-based-cache-expiration-動作します

結合ソリューションなし

編集:今、あなたがfollowingsテーブルに何億もの行を持っているなら、これが私がすることです:

  • テーブルにインデックスを付けてフィールドlast_followed_atを作成しますshows
  • Following.rbbelongs_to :show, touch: :last_followed_at。このように、に新しいエントリを追加するとすぐに、テーブルFollowingのフィールドが更新されますshows
  • 次に、最新のフォローされている番組を取得するには、次のようにします。

    @shows = Show.order("last_followed_at DESC").limit(10) # Fast query of course
    
于 2012-11-09T14:40:18.520 に答える
0

これは私の質問には答えませんが、私の問題は解決します。代わりにこれを行う方法は次のとおりです。

@shows = Rails.cache.fetch("recently_favorited_shows", expires_in: 1.minutes) do
  Show.find(Following.order("created_at DESC").limit(10).collect(&:show_id))
end

クエリはかなり高速です(それぞれ約0.8msがIRBコンソールを言います)

于 2012-11-10T14:48:52.777 に答える