0

我有一個簡單的發票和付款標準化模型。我應該在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

所以問題是,在這種情況下是一個非規範化的領域值得嗎,還是有更好的方法來實現呢?

回答

1

這取決於顯示或依賴未完成金額的用例。您多長時間使用此值,用戶是否會接受很少的延遲(考慮到計算此值的速度會很慢)只是爲了顯示此值,而您仍然可以及時顯示頁面上的所有其他信息?

您提到您尚未對此業務情景進行性能測試,也沒有關於處理髮票數量的系統範圍信息。與任何金融系統一樣,所有交易都傾向於與特定的財務期間相關聯,因此更適合考慮該期間而不是存儲在系統中的所有發票以訪問任何績效需求。

一般來說,沒有非標準化字段的處理過程應該能夠處理大量的發票,當然這也取決於您的服務器設置。此外,您仍然可以優化代碼並減少查詢數量以獲得相同的功能。

如果您還沒有看到性能方面的問題,您可能會嘗試過早優化,這並不總是最佳做法。所以我會考慮避免非規範化領域,直到我看到它的需求,然後在需要時做必要的優化。希望有所幫助。

+0

查詢更新發票的頻率大概在100比1左右。我不知道系統的最終大小,但不想限制其擴展能力。對於一個典型的小公司來說,每年可能有幾千張發票,但並不是很大。規範化的代碼運行除了獲取計數的錯誤,我可以爲此編寫另一個查詢。我同意DK對過早優化的看法。 –

+0

幾千張發票並不是一個值得擔心的大數字,所以如果沒有非規範化字段開始似乎是更好的選擇,然後根據需要進行優化。同樣對於計數,編寫代碼以獲取模型或控制器中的計數,然後將該值傳遞給erb而不是直接在erb中編寫代碼是更好的做法。 – coffeebytes

相關問題