我有以下表格:
Customer(customer_id) - 1000 rows (1000 customers)
Invoice(invoice_id, customer_id) - 1000000 rows (1000 invoices per customer)
Charge(charge_id, invoice_id, charge_amount) - 20000000 rows (20 charges per invoice)
现在,我正在尝试使用它的总费用来生成客户的发票。 结果表看起来像这样:
Customer_name | invoice_id | charge_total
test 1 $1000
test 2 $1200
test 3 $900
...
我的问题是,针对此案例的数据库设计的最佳做法是什么? 我正在思考以下两个选项:
谢谢大家!
答案 0 :(得分:5)
有两种方法可以看待这个问题。数据库纯粹主义者会说派生或计算的数据是多余的并且违反了第3范式。在编辑数据的事务系统中,这是一个问题,因为规范化会阻止您陷入自相矛盾的数据陷阱。
另一方面,有一种实用的观点认为,一次写入但从未更新的数据无论如何都不会更新和删除异常,因此冗余会占用磁盘空间,但不存在风险。
作为一项规则,我总是首先将数据库设计为规范化,然后在仔细检查竞争风险后,在有限的基础上引入冗余。
答案 1 :(得分:1)
这很难回答 - 你知道你有性能问题吗?我不会优化,除非我真的,真的不得不。 即便如此,我还是会考虑一个“发票归档”表来保存计算值。从逻辑上讲,计算摘要并将其存储在表格中以反映实际开具发票的金额(包括税金,运费等)并没有错。这意味着您可以存储发票数据的存档版本而无需担心。
我不想将它存储在主“发票”表中,除非发票是不可变的 - 你创建它,并且从创建它之时就没有任何变化。如果您有一个业务流程,其中预先创建了发票并且随着时间的推移将项目添加到其中,那么这不起作用。
答案 2 :(得分:0)
这个决定取决于用户速度与数据库中额外复杂性之间的权衡,使您的代码更容易出错。这让我想起了这个讨论:
https://stackoverflow.com/questions/211414/is-premature-optimization-really-the-root-of-all-evil
在您的情况下,由于您已经完成了性能测试,我觉得像您建议的那样对数据库进行非规范化是一件好事。
答案 3 :(得分:0)
您要记住的一件事是,数据的变化频率会影响“charge_total”的价值吗?例如,如果退回某个项目,该费用是否会在以后的日期从发票中扣除?如果事情经常发生变化,那么你必须记住让这些变更事件负责更新“charge_total”字段的开销。
答案 4 :(得分:0)
首先,您应该检查没有额外列的性能是否足够。如果不是,那么,而不是之前(!),你应该检查你的“快20倍”猜测是否真的正确。尝试为您的charge_total
添加一个View数据库,并测试数据库系统如何处理该视图。我不太了解MySql,但只要源数据不变,一些现代数据库系统就能够对视图数据进行内部缓存。
如果您已经完成了这项工作,而且您确定附加列charge_total
是您真正遇到的问题的解决方案,那么您应该确保这些冗余数据保持一致。您可以在数据库端(使用触发器)或在客户端执行此操作 - 当您拥有一个只更改您控制下的charges
表的过程时。
答案 5 :(得分:-1)
在charge_total
表中创建invoice
计算列可能是我能想到的最简单的方法。每次运行查询以获取值时,它都可以帮助您避免执行该计算,我假设更频繁地添加费用。
答案 6 :(得分:-3)
现在磁盘空间很便宜,所以你不必担心尺寸。如果额外的列提高了性能,那就去吧。