我对计数器缓存的概念不熟悉,并且在我的某个应用程序主页上有一些天文加载时间,我相信我需要继续使用它。
我需要实现的大多数计数器缓存都附加了某些(简单)条件。例如,这是一个常见的查询:
@projects = employee.projects.where("complete = ?", true).count
当我显示一个列出公司每个员工的项目计数的表单时,我遇到了上述N+1
查询问题。
我真的不知道我在做什么,所以请纠正我!
# new migration
add_column :employees, :projects_count, :integer, :default => 0, :null => false
# employee.rb
has_many :projects
# project.rb
belongs_to :employee, :counter_cache => true
迁移后...是我需要做的全部吗?
我如何在我提到的条件下工作,以尽量减少加载时间?
答案 0 :(得分:27)
关于counter_cache
的条件,我会阅读此blog post。
您应该做的一件事是将以下内容添加到迁移文件中:
add_column :employees, :projects_count, :integer, :default => 0, :null => false
Employee.reset_column_information
Employee.all.each do |e|
Employee.update_counters e.id, :projects_count => e.projects.length
end
因此,您当前的项目计数可以迁移到与每个Employee对象关联的新projects_count
。在那之后,你应该好好去。
答案 1 :(得分:13)
检查counter_culture gem:
counter_culture :category, column_name: Proc.new {|project| project.complete? ? 'complete_count' : nil }
答案 2 :(得分:7)
您不应使用“counter_cache”,而应使用自定义列:
rails g migration AddCompletedProjectsCountToEmployees completed_projects_count:integer
(如果需要,请将, :default => 0
添加到add_column行)
rake db:migrate
然后使用回调
class Project < ActiveRecord::Base
belongs_to :employee
after_save :refresh_employee_completed_projects_count
after_destroy :refresh_employee_completed_projects_count
def refresh_employee_completed_projects_count
employee.refresh_completed_projects_count
end
end
class Employee
has_many :projects
def refresh_completed_projects_count
update(completed_projects_count:projects.where(completed:true).size)
end
end
添加列后,您应该在控制台或迁移文件中进行初始化(在def up中):
Employee.all.each &:refresh_completed_projects_count
然后在您的代码中,您应该调用employee.completed_projects_count
以便访问它
答案 3 :(得分:6)
而不是update_counters
我使用update_all
您不需要Employee.reset_column_information
行并且速度更快,因为您正在进行单个数据库调用
Employee.update_all("projects_count = (
SELECT COUNT(projects.id) FROM projects
WHERE projects.employee_id = employees.id AND projects.complete = 't')")