Sử dụng counter cache để tăng performance cho rails application

I. Counter cache là gì?

Counter cache là kỹ thuật để tăng performance cho application thông qua việc tiết kiệm số lần gọi đến SQL.

Cách thực thi rất đơn giản nhưng đem lại hiệu quả khá cao.

Tình huống

Chúng ta có bảng lessons, có quan hệ 1-n (has_many) với bảng words. Để đếm được số words có trong 1 lessons

 lesson = Lesson.first
 number = lesson.words.count

Khi đó SQL phải joins lessons với words và đếm số bản ghi và trả về số lượng. Vấn đề sẽ nặng nhọc hơn nếu như số lượng lessons và words tăng lên.

=> giải pháp đưa số words làm 1 thuộc tính của lessons (words_count), cập nhật lại nó mỗi khi words thay đổi.

Mặc dù việc cập nhật lại số words của lesson hơi phức tạp 1 chút nhưng đã có gem counter_culture thay ta làm việc này. Lợi ích thu được là không cần phải đếm số words của lesson thông qua việc joins nữa, thay vào đó chỉ cần gọi

 lesson = Lesson.first
 number = lesson.words_count

II. Sử dụng gem counter_culture

1.Cài đặt

thêm counter_culture vào Gemfile:

gem 'counter_culture', '~> 0.1.33'

sau đó bundle install

thêm cột mới vào bảng lessons


rails generate counter_culture Lesson words_count

sau đó rake db:migrate

2. Sử dụng

a) counter-cache

class Word < ActiveRecord::Base
  belongs_to :lesson
  counter_culture :lesson
end

class Lesson < ActiveRecord::Base
  has_many :words
end

Vậy là xong. Khi bạn thêm sửa xóa words, gem sẽ tự đếm lại words_count của lesson tương ứng. Không tin bạn có thể thử! Thứ chúng ta cần chỉ là

 lesson = Lesson.first
 number = lesson.words_count

b) Multi-level counter-cache

class Product < ActiveRecord::Base
  belongs_to :sub_category
  counter_culture [:sub_category, :category]
end

class SubCategory < ActiveRecord::Base
  has_many :products
  belongs_to :category
end

c) tùy biến tên cột

class Product < ActiveRecord::Base
  belongs_to :category
  counter_culture :category, :column_name => "products_counter_cache"
end

class Category < ActiveRecord::Base
  has_many :products
end

d) Dynamic column name

class Product < ActiveRecord::Base
  belongs_to :category
  counter_culture :category, :column_name => proc {|model| "#{model.product_type}_count" }
end

class Category < ActiveRecord::Base
  has_many :products
end

d) counter cache có điều kiện (Bạn có thể tự áp dụng cho lessons-words với điều kiện chỉ đếm những words có thuộc tính right_word = true)

class Product < ActiveRecord::Base
  belongs_to :category
  counter_culture :category, :column_name => proc {|model| model.special? ? 'special_count' : nil }
end

class Category < ActiveRecord::Base
  has_many :products
end

III. Kết luận

Hi vọng các bạn thấy bài viết này hữu ích. Tham khảo: https://github.com/magnusvk/counter_culture