通常要計算 has_many 關聯資料的數量時,就會用以下方式。
但這樣就會產生很多SQL count查詢,造成效能上的問題
1
2
3
4
| SELECT * FROM `pages` LIMIT 5 OFFSET 0
SELECT count(*) AS count_all FROM `pages` WHERE (`pages`.book_id = 1 )
SELECT count(*) AS count_all FROM `pages` WHERE (`pages`.book_id = 2 )
SELECT count(*) AS count_all FROM `pages` WHERE (`pages`.book_id = 3 )
|
因此可以在 Book Model 上新增一個欄位,pages_count
,用來記錄該 book 的 page 數量,之後撈資料,就直接撈這個數字就可以了。
1
2
3
4
5
| def change
add_column :books, :pages_count, :integer, default: 0
end
#型態是 integer,記得設定 default 值
|
接著編輯兩邊的 model,Rails 內建有 counter_cache helper,可以直接去做計算!
1
2
3
4
5
6
7
8
9
| class Book < ActiveRecord::Base
has_many :pages
end
class Page < ActiveRecord::Base
belongs_to :book, :counter_cache => true
end
#設定成 ture,就會自動去找 pages_count 欄位,若要指定欄位則是 counter_cache: :count_of_pages
|
這樣之後下 @book.pages.size
的指令時 Rails 就會預設去找 pages_count
的欄位,不用重新下 SQL指令計算。
也可以直接下 @book.pages_count
最後注意,必須要用 create
和 destroy
才會 call back 更改數字,delete
則不會。
另外如果想要將數字重新計算可以用以下,可以直接在 rails c
裡面跑
也可以在新增 counter 的 migration 裡面直接加上去,在 db:migrat
的時候就會刷新了
1
2
3
| Page.pluck(:id).each do |i|
Page.reset_counters(i, :books)
end
|
官方文件:
Guides
Guides 中文
pluck
reset_counters