Подтвердить что ты не робот

Counter Cache для столбца с условиями?

Я новичок в концепции кэширования счетчиков и с некоторыми астрономическими временами загрузки на одной из основных страниц приложения, я считаю, что мне нужно идти по ней.

Большинство кешей-счетчиков, которые мне нужно реализовать, имеют определенные (простые) условия. Например, вот общий запрос:

@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

После миграции... это все, что мне нужно сделать?

Как я могу работать в условиях, о которых я говорил, чтобы минимизировать время загрузки?

4b9b3361

Ответ 1

Что касается условий с counter_cache, я бы прочитал этот пост в блоге.

Единственное, что вам нужно сделать, это добавить следующее в файл миграции:

 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

Таким образом, ваш текущий счетчик проектов может быть перенесен в новый projects_count, связанный с каждым объектом Employee. После этого вам должно быть хорошо идти.

Ответ 2

Проверьте counter_culture gem:

counter_culture :category, column_name: Proc.new {|project| project.complete? ? 'complete_count' : nil }

Ответ 3

Вы не должны использовать "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, чтобы получить к нему доступ

Ответ 4

Вместо 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')")