Кэширование сложных расчетов в модели Rails 3 - PullRequest
3 голосов
/ 05 марта 2011

Я новичок в Ruby / Rails, так что, возможно, это (надеюсь) простой вопрос, на который я просто не знаю ответа.

Я внедряю систему учета / выставления счетов в Rails, и япытаюсь отслеживать текущий баланс после каждой транзакции, чтобы отобразить его в представлении, как показано ниже:

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

Каждая транзакция (также известная как позиция) сохраняется в базе данных со всемивышеуказанные значения (дата, описание, сумма), за исключением баланса.Я не могу сохранить баланс для каждой транзакции в базе данных, потому что он может измениться, если что-то случится с более ранней транзакцией (например, платеж, который был проведен, впоследствии не прошел).Поэтому мне нужно рассчитать его на лету для каждой отдельной позиции, и значение для Баланса для отдельной позиции зависит от значения для отдельной позиции (Баланс = Баланс предыдущей отдельной позиции + Сумма для этой отдельной позиции, т.е.)

Так вот мой вопрос.Мой текущий (неумелый) способ сделать это состоит в том, что в моей модели LineItem у меня есть метод баланса, который выглядит следующим образом:

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

Это очень дорого, и мое представление загружается вечно, так как я вычисляюпредыдущий баланс позиции снова и снова и снова.Какой лучший способ сделать это?

1 Ответ

3 голосов
/ 05 марта 2011

Вы в основном платите цену за нежелание хранить баланс в каждой транзакции. Вы можете оптимизировать свою базу данных с помощью индексов и использовать кэши и т. Д .; но принципиально вы столкнетесь с проблемой, что вычисление баланса займет много времени, если у вас много транзакций.

Имейте в виду, что вы будете продолжать получать новые транзакции, и ваша проблема, таким образом, будет ухудшаться со временем.

Вы можете рассмотреть несколько вариантов дизайна. Во-первых, как упоминал Дуглас Лиз, вы можете хранить баланс в каждой транзакции. Если приходит транзакция с более ранним сроком, это означает, что вам может потребоваться обновить несколько транзакций с этой даты. Однако он имеет верхнюю границу (в зависимости от того, сколько «старых» транзакций вы хотите разрешить), поэтому он имеет разумное поведение в худшем случае.

Кроме того, вы можете сделать шаг согласования. Каждый месяц вы «закрываете книги» по транзакциям старше X недель. После сверки вы сохраняете Баланс, который вы рассчитали. В def balance вы теперь используете существующую логику, но также ссылаетесь на «баланс по состоянию на предыдущую сверку». Это опять-таки обеспечивает разумный и предсказуемый сценарий наихудшего случая.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...