简体   繁体   English

我应该在Ruby on Rails中使用未修饰的字段表示未偿金额吗

[英]Should I use a denormaized field for amount outstanding in Ruby on Rails

I have a simple normalized model for invoices and payments. 我有一个简单的发票和付款标准化模型。

The relevant fields are 相关领域是

invoices.id
invoices.amount_with_tax
invoice_payments.id

invoice_payments.invoice_id
invoice_payments.amount

The relations are 关系是

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

The Payment model is not relevant to this question but exhibits the same problem. 付款模式与此问题无关,但存在相同的问题。

The variables invoices and @invoices are ActiveRecord relations. 变量invoices@invoices是ActiveRecord关系。

If I add an amount_outstanding field to the invoice table the code to get unpaid invoices is simple: 如果我在发票表中添加一个amount_outstanding字段,那么获取未付发票的代码很简单:

invoices.where('amount_outstanding > 0')

but the maintenance of the denormalized field is a nuisance. 但是对非规范化字段的维护很麻烦。

My current code to get this without that field is complex: 我目前没有该字段的代码很复杂:

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')

I have not done any performance testing on this, but it looks like it won't be very good when there are a lot of invoices in the system. 我没有对此进行任何性能测试,但是当系统中有很多发票时,它看起来可能不是很好。 The code generated by ActiveRecord is similar to the code I'd write in SQL, so it wouldn't be horrible. ActiveRecord生成的代码与我在SQL中编写的代码相似,因此不会太可怕。

Similar code will be needed on the Payment side to find payments that are not completely accounted to invoices. 付款方需要类似的代码来查找未完全计入发票的付款。

Finding unpaid invoices is a frequent operation, as is reporting the amount outstanding. 查找未付的发票是很常见的操作,报告未结金额也很常见。 For a well run company the amount of uncollected accounts receivable is small compared to that which has been paid. 对于经营良好的公司,未收应收账款的金额与已付账款的金额相比很小。 Over time it will become a much smaller percentage of the total invoices. 随着时间的流逝,它将占总发票的比例要小得多。

Applying a payment to an invoice is usually done once and they are rarely reverted or edited. 通常将付款应用于发票一次,并且很少还原或编辑它们。 Most payments relate to one invoice and cover it completely. 大多数付款与一张发票有关,并且完全涵盖了该发票。

Also attempting to determine if there are unpaid invoices or getting their count in erb eg <%=@invoices.count %> returns a SQL error. 此外,尝试确定是否有未付款的发票或在erb中获取它们的计数,例如<%=@invoices.count %>返回SQL错误。

I personally do not like denormalized data, since the work to maintain it is usually about triple that of leaving it normalized. 我个人不喜欢非规范化数据,因为维护该数据的工作通常是保持规范化的三倍。 In this case the field must be updated if amount_with_tax changes, or if the InvoicePayment is edited, deleted or moved to another invoice. 在这种情况下,如果amount_with_tax更改,或者如果InvoicePayment已被编辑,删除或移动到另一张发票,则必须更新该字段。 The code to calculate the value of the amount_outstanding however is very simple for a single invoice: 但是,对于单个发票,用于计算amount_outstanding值的代码非常简单:

paid = invoice_payments.sum(:amount)
self.amount_outstanding = self.amount_with_tax - paid
save

I'm currently using callbacks on the Invoice and InvoicePayments models to maintain the amount_outstanding . 我目前在Invoice和InvoicePayments模型上使用回调来维护amount_outstanding

So the question is, is a denormalized field worth it in this case or is there a better way to achieve this? 所以问题是,在这种情况下,非规范化字段值得吗?或者有更好的方法来实现这一点?

It depends a lot on use cases that display or rely on amount outstanding. 这在很大程度上取决于显示或依赖于未偿还金额的用例。 How often do you use this value and will the users accept little delay (considering that it would be slow to compute this value) just to display this value while you can still display all other information on the page promptly? 您多久使用一次该值,并且用户仍会接受很少的延迟(考虑到计算此值会很慢),只是为了显示此值,而您仍可以立即在页面上显示所有其他信息?

You mentioned you have not done performance testing for this scenario and also there is no information on the scope of system in terms of number of invoices processed. 您提到您尚未针对此业务情景进行性能测试,并且就处理的发票数量而言,也没有关于系统范围的信息。 As with any financial system, all the transactions tend to be associated with a particular financial period, so its more appropriate to consider that period instead of all the invoices stored in the system to access any performance needs. 与任何财务系统一样,所有交易都倾向于与特定财务期间相关联,因此更适合考虑该期间而不是系统中存储的所有发票以访问任何绩效需求。

In general, the processing that is required without denormalized field should be able to handle quite a large number of invoices and of course it will depend on your server setup too. 通常,不使用非规范化字段所需的处理应能够处理大量发票,当然,这也将取决于您的服务器设置。 Also there is a possibility that you can still optimize the code and reduce the number of queries to get the same functionality. 还有一种可能性,您仍然可以优化代码并减少查询次数以获得相同的功能。

If you haven't already seen the issues with performance, you might be attempting premature optimization which is not always a best practice. 如果您还没有发现性能问题,则可能正在尝试过早的优化,但这并不总是最佳实践。 So I would consider avoiding denormalized field until I see the need for it and then do the necessary optimization as and when needed. 因此,我会考虑避免使用非规范化字段,直到我看到需要它为止,然后在需要时进行必要的优化。 Hope that helps. 希望能有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM