[Rails] 透過計數快取 Counter Cache 提升效能
在許多場合需要統計 has_many
一對多關聯的資料數量,若使用單純的 Rails 關聯查詢,則每次讀取頁面都會重新再統計一次,影響網站效能。
情境
專案Project
model has many 任務Task
.
Project
model
projects_controller.rb
views/projects/index.html.erb
讀取頁面時就會出現 N+1 Query 問題,1 個專案若有 3 個任務便會做 3 + 1 次查詢:SELECT “tasks”.* FROM “tasks” WHERE “tasks”.”project_id” = ?
使用方法
在 projects
table 中建立 tasks_count 欄位,將計數存在其中,
更新專案的任務數量時,counter cache 會同步更新到對應的欄位裡面。
建立 migration
rails g migration add_tasks_count
編輯剛建立的 migration 檔:
在程式碼第一行加入 # frozen_string_literal: true 凍結此檔,可以稍微加快往後的讀取速度。
執行 rails db:migrate
編輯 Task
model
開啟 counter cache:
如果想指定其他欄位儲存 counter cache 請改寫為
counter_cache: ‘COLUMN_NAME’
確認資料表內容 schema.rb
建立 rake task 更新 counter cache
更新既有 projects 的 tasks count lib/tasks/update_tasks_count.rb
這邊使用我在五倍紅寶石學到的技巧,將這段 rake task 整理在 namespace db 之下。
查看指令確認一下沒有寫錯:rails -T
執行 rails db:updste_tasks
重啟伺服器
再次讀取頁面查看 SQL queries 只剩一行: SELECT “projects”.* FROM “projects”
大功告成!