何时存储预先计算的值与在检索它们时计算它们?

时间:2012-07-06 10:47:41

标签: database database-design normalization denormalization

我陷入两难境地。我正在使用大量遗留代码,我在表结构中看到了很多冗余信息。它们主要以两种形式存在:

一个。保存在“连接”上的冗余信息。例如:

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的引用),代码将保存此处的“计算”值。再一次,理由是“速度”,常态射到了地狱。

我有两个问题:

  1. 我可以告诉新开发人员这些结构没有规范化,但他们可以更快地说出来。我该如何反击?我反驳了吗?其他人是否像这样构建他们的数据库?!
  2. 是否有经验法则或一套原则可以用来说 - '哦,它会慢一点,但只有1%,所以可以这样做这个方式'等?

2 个答案:

答案 0 :(得分:16)

关于你的两个问题:

  

我可以告诉新开发人员这些结构没有规范化,   但他们可以说更快。我该如何反击?我反驳了吗?   其他人是否像这样构建他们的数据库?!

它可能更快,但并不一定如此:每当您决定向表中添加额外信息时(在您的情况下为额外字段),您也会因为表变大而增加性能损失,这可能意味着更多数据从服务器传输到客户端,或者被分页在内存中或从内存中分页...如果该字段用于加速查询,它可能会有一个或多个索引,这在更新和插入期间也会有性能损失。 不过,主要观点是我在评论中暗示的那个:“缓存”和“预先计算”的值使得系统在数据完整性方面更加脆弱。 你确定“event_creator_id”始终正确指向真正的创作者,即使有人修改了原始值吗?如果是的话,这也有成本,无论是在计算方面(你必须在更改创建者时更新所有表),还是在实际开发和测试工作方面(你确定没有人忘记将更改传播到预先计算的字段? )。

对于“折扣价”或运行总计等聚合值也是如此......并且更改原始数据可能比更改“事件创建者”信息更频繁。同样,是否有适当的“缓存失效”机制,以确保每当有人完成销售时重新计算总销售额?退货项目怎么样?有人考虑过确保诚信的成本吗?

运行总计和其他派生值应该通过使用视图来实现,以便实际的DBMS引擎执行缓存(如果有的话),谁知道如何正确处理它。

  

是否有经验法则或一套我可以使用的原则   说 - '哦,它会慢一点,但只有1%,所以可以这样做   这样'等等?

数据库(或者可以说是任何类型的计算系统)应该“首先正确”,以便您可以找到如何使其“足够快,第二”。 交易的速度正确性是您在设计数据库时不应该采取的决定,除非您已经知道时效性被认为比正确性更重要。即您的要求明确指出,可能有错误或过时的信息不如响应时间重要。

换句话说:设计具有冗余缓存信息的表是过早优化的另一个例子,应该不惜一切代价避免。

另见this - 特别是答案

答案 1 :(得分:0)

我读过关于关系设计的任何数据库书总是包含一个关于"计划"冗余或"有限"去正常化。这取决于环境。富国银行预先计算银行对账单总额并存储预先计算。

想象一下,如果他们在打印语句时等待每个周期的结束,那么进行这些计算需要多长时间。

计划冗余正常!