복붙노트

[RUBY-ON-RAILS] 조건을 가진 열에 대한 카운터 캐시?

RUBY-ON-RAILS

조건을 가진 열에 대한 카운터 캐시?

나는 카운터 캐싱의 개념과 내 응용 프로그램의 메인 페이지 중 하나에 대한 몇 가지 천문학적로드 시간에 새로운 오전, 나는 그것을 가야 할 필요가있다 생각합니다.

카운터의 대부분은 내가 연결된 특정 (단순) 조건을 구현해야 캐시합니다. 예를 들어, 다음은 일반적인 쿼리는 다음과 같습니다

@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

마이그레이션 후 ... 모든 I 필요가해야 할 것입니다?

로드 시간을 최소화하기 위해 어떻게 내가 그렇게 언급 한 조건에서 작동 할 수 있습니까?

해결법

  1. ==============================

    1.counter_cache와 조건에 관해서,이 블로그 게시물을 읽을 것입니다.

    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로 마이그레이션받을 수 있습니다. 그 후, 당신은 갈 수 있어야한다.

  2. ==============================

    2.counter_culture 보석을 확인합니다 :

    counter_culture 보석을 확인합니다 :

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

    3.당신은 "counter_cache"이 아니라 사용자 정의 열을 사용하지 않아야합니다 :

    당신은 "counter_cache"이 아니라 사용자 정의 열을 사용하지 않아야합니다 :

    rails g migration AddCompletedProjectsCountToEmployees completed_projects_count:integer
    

    (추가, 상기 add_column 라인에 기본 => 0 당신이 원하는 경우)

    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까지의) 콘솔 또는 마이그레이션 파일에 초기화해야한다 :

    Employee.all.each &:refresh_completed_projects_count
    

    그런 다음 코드에서, 당신은 액세스하기 위해 employee.completed_projects_count 호출해야합니다 그것

  4. ==============================

    4.대신 update_counters의 난 update_all 사용

    대신 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')")
    
  5. from https://stackoverflow.com/questions/5347323/counter-cache-for-a-column-with-conditions by cc-by-sa and MIT license