少於 1 分鐘閱讀

前言

最近發現常常使用 conuter cache,紀錄一下增加記憶。

使用時機

當有兩個 table 為 1對多關聯,並需要統計關聯 table 的數量時。此時每次存取網頁都需要再統計一次數量,會造成效能低落。 若使用Counter Cache,則可讓每次關聯 table 數量異動時,由程式自動紀錄至主要 table 的 cache 欄位中,之後在網頁存取時就可以直接從 cache 抓取數量,讓使用者感到效能提升。

使用方式

例如: 顯示文章列表(posts)時,也要顯示每篇有多少留言回覆(comments)。

<% @posts.each do |post| %>
  主題:<%= post.subject %>
  回覆數:<%= post.comments.size %>
<% end %>

此時在取得 post.comments.size 時,實際上存取資料庫(select)的次數會是 comments 的數量

改使用 counter cache,需在 Model 新增一個欄位叫做 comments_count:

rails g migration add_comments_count_to_post comments_count:integer

至 Migration 調整,將 default 設為 0,並把 counter cache 初始化:

class AddPostsCountToTopic < ActiveRecord::Migration
  def change  
    add_column :posts, :comments_count, :integer, :default => 0  #補上 :defalut => 0
    
    Post.pluck(:id).each do |i| ## Post.pluck(:id),表示從Post中取得由id組成的array如[1,2,3,..]
      Post.reset_counters(i, :comments) ## 把所有counter cache重算一次
    end
  end
end

編輯 Models,加入 counter_cache: true

class Comment < ActiveRecord::Base
  belongs_to :post, counter_cache: true
end
class Post < ActiveRecord::Base
  has_many :comments
end

此時再執行

rake db:migrate

這樣同樣的 @post.comments.size,程式就會自動改抓 cache,就等於自動使用 @post.comments_count

備註

  1. 若不想使用comments_count當欄位名稱,改使用xxx當欄位名稱,可改寫為counter_cache: :xxx
  2. pluck用法參考
  3. reset_counters用法參考

參考

  1. https://ihower.tw/rails4/performance.html
  2. http://apidock.com/rails/ActiveRecord/Calculations/pluck
  3. http://apidock.com/rails/ActiveRecord/CounterCache/reset_counters

留言