我陷入两难境地。我正在使用大量遗留代码,我在表结构中看到了很多冗余信息。它们主要以两种形式存在:
一个。保存在“连接”上的冗余信息。例如:
event_id, event_name, event_creator_id
3 test1 43
subevent_id, event_id, event_creator_id
21 3 43
请注意event_creator_id的重复项。以前的“高级”开发人员给出的基本原理是,当我们需要事件创建者ID时,我们只需查询一个表而不进行“昂贵”连接来检索该值。
B中。冗余信息以节省计算。例如:
event_id, event_default_price
3 100
discount_id, discount_code, discount_percentage
7, ABCD, 50
special_event_id, event_id, discount_id, discounted_price
21 3 7, 50
请注意,代替为此特殊事件计算最终'discounted_price'(因为已经存在对discount_id的引用),代码将保存此处的“计算”值。再一次,理由是“速度”,常态射到了地狱。
我有两个问题:
答案 0 :(得分:16)
关于你的两个问题:
我可以告诉新开发人员这些结构没有规范化, 但他们可以说更快。我该如何反击?我反驳了吗? 其他人是否像这样构建他们的数据库?!
它可能更快,但并不一定如此:每当您决定向表中添加额外信息时(在您的情况下为额外字段),您也会因为表变大而增加性能损失,这可能意味着更多数据从服务器传输到客户端,或者被分页在内存中或从内存中分页...如果该字段用于加速查询,它可能会有一个或多个索引,这在更新和插入期间也会有性能损失。 不过,主要观点是我在评论中暗示的那个:“缓存”和“预先计算”的值使得系统在数据完整性方面更加脆弱。 你确定“event_creator_id”始终正确指向真正的创作者,即使有人修改了原始值吗?如果是的话,这也有成本,无论是在计算方面(你必须在更改创建者时更新所有表),还是在实际开发和测试工作方面(你确定没有人忘记将更改传播到预先计算的字段? )。
对于“折扣价”或运行总计等聚合值也是如此......并且更改原始数据可能比更改“事件创建者”信息更频繁。同样,是否有适当的“缓存失效”机制,以确保每当有人完成销售时重新计算总销售额?退货项目怎么样?有人考虑过确保诚信的成本吗?
运行总计和其他派生值应该通过使用视图来实现,以便实际的DBMS引擎执行缓存(如果有的话),谁知道如何正确处理它。
是否有经验法则或一套我可以使用的原则 说 - '哦,它会慢一点,但只有1%,所以可以这样做 这样'等等?
数据库(或者可以说是任何类型的计算系统)应该“首先正确”,以便您可以找到如何使其“足够快,第二”。 交易的速度正确性是您在设计数据库时不应该采取的决定,除非您已经知道时效性被认为比正确性更重要。即您的要求明确指出,可能有错误或过时的信息不如响应时间重要。
换句话说:设计具有冗余缓存信息的表是过早优化的另一个例子,应该不惜一切代价避免。
另见this - 特别是答案
答案 1 :(得分:0)
我读过关于关系设计的任何数据库书总是包含一个关于"计划"冗余或"有限"去正常化。这取决于环境。富国银行预先计算银行对账单总额并存储预先计算。
想象一下,如果他们在打印语句时等待每个周期的结束,那么进行这些计算需要多长时间。
计划冗余正常!