2013-05-08 5 views
2

나는 여러 카운터 캐시가있는 db 스키마를 사용하고 있습니다. 카운터 캐시를 여러 테이블에 분산시키는 대신 모든 다양한 카운터 캐시가있는 user_counters라는 테이블을 갖고 싶습니다. 대부분 사용자와 동일한 ID가되지 않습니다, 관련 사용자에 대한 UserCounter 기록을레일 카운터 캐시

def update_user_counter(column, user_id) 
    UserCounter.increment_counter(column, user_id) 
end 

을하지만 :이 같은 방법으로 서비스 객체에서 이러한 캐시를 업데이트 할 것입니다. 제가하고 싶은 것은 다음과 같습니다 :

def update_user_counter(column, user_id)  
    UserCounter.increment_counter(column, UserCounter.where('user_id = "#{user_id}"') 
end 

나는 이것을 어떻게 할 수 있습니까? 감사!!

+0

호기심 : 왜? 새로운 코드를 작성하는 데 심각한 기술적 빚이 있습니다. 따라서이 스키마는 어떤 이점을 제공합니까? – Matchu

+0

좋은 질문 ...이 user_counters 테이블에는 많은 페이지 뷰에서 사용되는 약 10 개의 카운터 캐시 열이 있습니다. 따라서 10 개의 개별 쿼리를 실행하여 10 개의 캐시 된 카운터 값을 얻는 대신 1 개의 쿼리를 실행할 수 있습니다. 다른 캐싱 전략 (예 : memcached)이 없기 때문에 가장 효율적인 대체 접근 방식처럼 보입니다. –

+0

데이터베이스 내부에서 트리거를 사용하여 이것을 구현할 생각이십니까? 그래, 그래, 레일스는 데이터베이스에 어떤 논리가 있어야한다고 생각하지 않지만 때로 레일스는 어리 석고 짧다. –

답변

2

사용자와 관련된 10 개의 속성 인 경우 단순히 사용자 모델에 포함시키지 않는 이유가 있습니까? 이 경우 아래 코드가 여전히 작동합니다 (UserCounter 대신 User의 일부로 만 사용).

당신이 원하는대로 구현하고 싶다면 먼저 user_counters 테이블에 user_id에 대한 인덱스가 있어야합니다 (레일스는 인덱스와 FK를 추가하는 것에 대해 바보이기 때문에).

class SomeOtherModel < ActiveRecord::Base 
    #Model code 

    def update_counter(user) 
    UserCounter.update_user_counter(:this_column, user.id) 
    end 
end 

이 솔루션 (또는 update_counter 방법을 사용하여) :

class UserCounter < ActiveRecord::Base 
    #other code 

    def self.update_user_counter(column, user_id) 
    counter = UserCounter.find_by_user_id(user_id) 
    counter.update_attribute(column, counter.read_attribute(column) + 1) 
    counter.save! 
    end 
end 

그리고 다른 모델 :

그런 다음 (상징으로 "열"전달)이 작업을 수행 할 수 둘 다 두 개의 데이터베이스 히트를 필요로합니다. 하나는 조회 용이고 다른 하나는 갱신 용입니다. 당신은 속도가 필요하면, 당신은 SQL에서 직접이를 작성할 수

query = "UPDATE user_counters SET #{column} = #{column} + 1 WHERE user_id = #{user_id};" 
ActiveRecord::Base.connection.execute(query); 

user_iduser_counters에 고유 한 것으로 가정합니다.

+0

제안을 주셔서 감사합니다. - 현재 사용자 모델에 있지만 모델이 실제로 너무 뚱뚱해지고 모델의 일부로 카운터를로드하는 작업이 너무 무거워지고 있습니다. 나는 increment_counter 메소드보다 먼저 찾을 수 있다는 것을 알았지 만, 런타임시에 (user_id에 기반하여) 카운터 행 ID를 동적으로 얻는 방법을 찾고있었습니다 - increment_counter가 원시 SQL 명령을 실행한다는 사실을 이용하십시오. –

+0

'UserCounter.where (user_id : user_id) .id'는 원시 SQL에 필요한 UserCounter 행 ID를 반환합니다. 어느 쪽이든, 당신은 DB를 두 번 왕복하고 있습니다 (하나는 조회를위한 것이고 하나는 증가를위한 것입니다). 위의 답변을 업데이트하면 내가 생각하는 바가 포함될 것입니다. – mikeryz

+0

당신의 제안에 감사드립니다! 기술적으로 올바른 답변을 표시했습니다. 불행히도, 언급 한 바와 같이 여전히 db에 대해 두 번의 왕복이 있기 때문에 이것은 차선책입니다. 어쩌면 내가 직접 increment_counter 메서드를 만들어 작업을 수행 할 것이다. 그 사이에, 더 큰 물고기를 튀기는 것에. –