我有一個簡單的發票和付款標準化模型。我應該在Ruby on Rails中使用一個denormaized字段來處理未完成金額
相關字段是
invoices.id
invoices.amount_with_tax
invoice_payments.id
invoice_payments.invoice_id
invoice_payments.amount
的關係
Invoice
has_many :invoice_payments
has_many :payments, through: :invoice_payments
InvoicePayment
belongs_to :invoice
belongs_to :payment
Payment
has_many :invoice_payments
has_many :invoices, through: :invoice_payments
支付模式是不相關的這個問題,但表現出了同樣的問題。
變量invoices
和@invoices
是ActiveRecord關係。
如果我添加一個amount_outstanding
場發票表中的代碼來獲得未付發票很簡單:
invoices.where('amount_outstanding > 0')
但非規格化場的維護是一個麻煩。
我當前的代碼來獲得這個沒有那場是複雜的:
invoices = invoices.left_outer_joins(:invoice_payments)
invoices = invoices.distinct.select('invoices.*, sum(invoice_payments.amount) as total_payments')
invoices = invoices.group('invoices.id')
invoices = invoices.having('sum(invoice_payments.amount) < invoices.amount_with_tax or sum(invoice_payments.amount) is null')
我沒有做過任何這性能測試,但它看起來像它不會是很好的時候有很多的系統中的發票。 ActiveRecord生成的代碼類似於我在SQL中編寫的代碼,所以它不會太糟糕。
支付方需要類似的代碼才能找到未完全計入發票的付款。
找到未付發票是一項頻繁的操作,同時報告未付金額。對於一家經營良好的公司來說,未收回的應收賬款數額與已支付的數額相比較小。隨着時間的推移,它將佔發票總額的很小一部分。
對發票應用付款通常會執行一次,而且很少還原或編輯它們。大多數付款與一張發票相關並完全覆蓋。
還試圖確定是否有未付的發票或在erb中獲得他們的計數,例如, <%[email protected] %>
返回SQL錯誤。
我個人不喜歡非規範化的數據,因爲維護它的工作通常是將其保持正常化的三倍。在這種情況下,如果amount_with_tax
更改,或者InvoicePayment
被編輯,刪除或移動到另一個發票,則該字段必須更新。但是計算amount_outstanding價值的代碼是一個單一的發票很簡單:
paid = invoice_payments.sum(:amount)
self.amount_outstanding = self.amount_with_tax - paid
save
我目前使用的發票回調和InvoicePayments車型保持amount_outstanding
。
所以問題是,在這種情況下是一個非規範化的領域值得嗎,還是有更好的方法來實現呢?
查詢更新發票的頻率大概在100比1左右。我不知道系統的最終大小,但不想限制其擴展能力。對於一個典型的小公司來說,每年可能有幾千張發票,但並不是很大。規範化的代碼運行除了獲取計數的錯誤,我可以爲此編寫另一個查詢。我同意DK對過早優化的看法。 –
幾千張發票並不是一個值得擔心的大數字,所以如果沒有非規範化字段開始似乎是更好的選擇,然後根據需要進行優化。同樣對於計數,編寫代碼以獲取模型或控制器中的計數,然後將該值傳遞給erb而不是直接在erb中編寫代碼是更好的做法。 – coffeebytes