2011-03-05 2 views
3

Ruby/Rails를 처음 사용하기 때문에 (아마도 잘) 단순한 질문 일뿐입니다.Rails 3 모델에서 복잡한 계산 캐쉬

나는 레일의 회계/결제 시스템을 구현하고, 나는 다음과 같이 뷰에 표시하기 위해 각 거래 후 실행 균형을 추적하기 위해 노력하고있어 :

 
Date  Description  Charges($) Credits($) Balance($)
Mar 2 Activity C $4.00 -$7.50
Feb 25 Payment for Jan $8.00 -$3.50
Feb 23 Activity B $1.50 -$11.50
Feb 20 Activity A $2.00 -$10.00

각 거래 (광고 항목이라고도 함)는 데이터베이스에 저장되며 잔액을 제외한 모든 값 (날짜, 설명, 금액)이 저장됩니다. 나는 이전 거래가 일어 났을 때 변할 수 있기 때문에 데이터베이스의 각 거래에 대한 잔액을 저장할 수 없다. 그래서 각 광고 항목에 대해 즉시 계산해야하며 광고 항목의 잔액 값은 이전 광고 항목의 값에 따라 다릅니다 (잔액 = 이전 광고 항목의 잔액 +이 광고 항목의 금액, 즉)

여기 내 질문이 있습니다. 이것은 매우 비용이 많이 드는 내보기 내가 이전을 계산하고있어 이후로드 영원히 소요

def balance 
    prev_balance = 0 
    #get previous line items balance if it exists. 
    last_line_item = Billing::LineItem.get_last_line_item_for_a_ledger(self.issue_date,self.ledger_item_id) 

    if last_line_item 
    prev_balance = last_line_item.balance 
    .. some other stuff... 
end 

prev_balance + (-1*net_amount) # net_amount is the amount for the current line item 
end 

: 그 일을 내 전류 (무능) 방법은 내 LineItem을 모델에서, 나는처럼 보이는 밸런스 방법을 가지고있다 광고 항목의 잔액을 계속 반복해서 표시합니다. 이 작업을 수행하는 더 좋은 방법은 무엇입니까?

+0

첫 번째 LineItem에 대한 잔액을 계산하지 않고 모든 항목을 반복하면서 현재 잔액을 추적 할 수 있습니까? – Olives

+0

eager loading association과 같은'get_last_line_item_for_a_ledger'에 할 수있는 최적화가 있습니까? 데이터베이스 필드의 색인이 생성 되었습니까? –

+0

나는 당신과 같은 시스템을 가지고있다. 거래와 균형이 있어야한다. 돈이 아니라 주식이다. 거래 내역을 직접 저장합니다. 트랜잭션이 업데이트 될 때마다 다음 트랜잭션을 모두 업데이트하므로 잔액을 표시해야 할 때 이미 계산됩니다. 기본 구현은 아니지만 데이터 양이 많고 성능이 매우 중요한 경우 도움이 될 수 있습니다. –

답변

3

기본적으로 각 거래에서 잔액을 저장하지 않으려 고하기 때문에 가격을 지불하고 있습니다. 인덱스로 데이터베이스를 최적화하고 캐시 등을 사용할 수 있습니다. 근본적으로 당신은 많은 거래가있는 경우 잔액을 계산하는 데 오랜 시간이 걸리는 문제에 봉착하게됩니다.

새로운 거래가 계속 발생하므로 문제가 시간이지나면서 악화됩니다.

몇 가지 디자인 대안을 고려해 볼 수 있습니다. 먼저 Douglas Lise가 언급 한 것처럼 각 거래마다 잔액을 저장할 수 있습니다. 초기 거래가 시작된 경우 해당 날짜 이후에 여러 거래를 갱신해야 할 수도 있습니다. 그러나 이것은 상한을 가지므로 ("오래된"트랜잭션을 어떻게 허용 하느냐에 따라) 합리적인 최악의 경우 동작을합니다.

또는 조정 단계를 수행 할 수 있습니다. 매월 X 주보다 오래된 거래에 대해 "책을 닫습니다". 화해 후에 계산 한 잔액을 저장합니다. def balance에서 기존 논리를 사용하지만 "이전 조정의 잔액"을 참조하십시오. 이것은 다시 합리적이고 예측 가능한 최악의 시나리오를 제공합니다.