数据库历史

时间:2012-06-11 19:50:39

标签: mysql database-design

在我们的应用程序中,我们需要存储引用以供以后访问。

示例:用户可以一次提交发票,此发票包含的所有参考(客户地址,计算的金额,产品说明)和计算应该随着时间的推移而存储。

我们需要以某种方式保留参考文献,但如果产品名称有变化吗?因此,某种程度上我们需要复制所有内容,以便以后记录,不会受到未来变化的影响。即使删除了产品,也需要在以后存储发票时进行审核。

此处有关数据库设计的最佳做法是什么?即使是最灵活的方法,例如当用户想要稍后编辑他的发票并从数据库恢复?

谢谢!

5 个答案:

答案 0 :(得分:10)

这是一种方法:

enter image description here

基本上,我们从不修改或删除现有数据。我们通过创建新版本来“修改”它。我们通过设置DELETED标志来“删除”它。

例如:

  • 如果产品更改价格,我们会在PRODUCT_VERSION中插入新行,而旧订单会保持与旧PRODUCT_VERSION和旧价格的连接。
  • 当买家更改地址时,我们只需在CUSTOMER_VERSION中插入一个新行并将新订单链接到该行,同时保持旧订单链接到旧版本。
  • 如果产品被删除,我们并不会真正删除它 - 我们只需设置PRODUCT.DELETED标志,因此历史上为该产品制作的所有订单都保留在数据库中。
  • 如果客户被删除(例如因为他请求取消注册),请设置CUSTOMER.DELETED标志。

注意事项:

  • 如果产品名称必须是唯一的,则无法在上述模型中以声明方式强制执行。您需要将NAME从PRODUCT_VERSION“推广”到PRODUCT,将其作为密钥并放弃“发展”产品名称的能力,或仅在最新的PRODUCT_VER(可能通过触发器)强制执行唯一性。
  • 客户的隐私存在潜在问题。如果客户从系统中删除,可能需要从数据库中物理删除其数据,只需设置CUSTOMER.DELETED就不会这样做。如果这是一个问题,要么删除所有客户版本中的隐私敏感数据,要么将现有订单与真实客户断开连接并将其重新连接到特殊的“匿名”客户,然后实际删除所有客户版本。

该模型使用了大量的识别关系。这导致“胖”外键并且可能有点存储问题,因为MySQL不支持前沿索引压缩(不像甲骨文),但另一方面InnoDB always clusters the data就PK而且这个聚类可以有益于性能。此外,JOINs不太必要。

具有非识别关系和代理键的等效模型如下所示:

enter image description here

答案 1 :(得分:1)

您可以在产品表中添加一个列,指示是否正在销售。然后当产品被删除时#34;您只需设置该标志,使其不再作为新产品提供,但您保留数据以供将来查找。

要处理名称更改,您应该使用ID来引用产品而不是直接使用名称。

答案 2 :(得分:1)

我确信您遇到的问题是数据库规范化的结果。解决此问题的方法之一可以从商业智能技术中获取 - 将数据归档为Data Warehouse中的非规范化状态。

规范化数据:

  • 订单表
    • 的OrderId
    • 客户ID
  • 客户表
    • 客户ID
  • 项目表
    • 项目Id
    • ITEMNAME
    • ITEMPRICE
  • OrderDetails表
    • ItemDetailId
    • 的OrderId
    • 项目Id
    • ItemQty

查询并存储非规范化时,数据仓库表看起来像

  • 的OrderId
  • 客户ID
  • 客户名称
  • CustomerAddress
  • (其他客户字段)
  • ItemDetailId
  • 项目Id
  • ITEMNAME
  • ITEMPRICE
  • (其他订单详情和项目字段)

通常,有某种预定作业会按计划将数据从规范化数据提取到数据仓库中,或者如果您的设计允许,则可以在订单达到某个状态时完成。 (例如发货)可能是记录在每次状态变化时存储(使用名为OrderStatus的字段来处理当前状态),因此完全去标准化的数据可用于oprder /履行过程的每个步骤。何时以及如何将数据存档到仓库中将根据您的需求而变化。


上面涉及很多开销,但我所知道的另一种常见方法带来了更多的开销。

另一种方法是将表格设为只读。如果客户想要更改其地址,则不会编辑其现有地址,而是插入新记录。

因此,当我第一次在Jamnuary的网站上订购时,如果我的地址是AddressId 12,那么我将在7月4日移动,我将新的AddressId绑定到我的帐户。 (比如AddressId 123123,因为您的网站非常成功并吸引了大量客户。)

我在7月4日之前订购的订单会将AddressId 12与它们相关联,并且在7月4日或之后发出的订单具有AddressId 123123.

对每个需要保留历史数据的表重复该模式。


我确实有第三种方法,但搜索很困难。我只在一个应用程序中使用它,并且它实际上在这个单个实例中运行良好,它具有一些非常具体的业务需求,可以完全按照特定时间点重建数据。除非我有类似的业务需求,否则我不会使用它。

在特定状态下,将数据序列化为Xml文档或可用于重建数据的其他文档。这使您可以保存数据序列化时的数据,保留原始表结构和关联。

答案 3 :(得分:1)

你在纯粹主义和实践方法之间开辟了一场永恒的辩论。

从数据库的标准化角度来看,您“应该”保留所有相关数据。换句话说,如果产品名称发生变化,请保存更改日期,以便您可以及时返回并使用该产品名称重建发票,以及当天存在的所有其他数据。

“de”规范化方法是将发票视为“时刻”,在相关表格中记录实际当天的数据。这种方法可以让您在没有任何依赖性的情况下提取该发票,但您永远无法从头开始重新创建该发票。

答案 4 :(得分:0)

如果您有时间敏感数据,则可以使用product和Customer表之类的内容作为查找表,并将信息直接存储在Orders / orderdetails表中。

因此订单表可能包含客户名称和地址,详细信息包含有关产品的所有相关信息,包括特别是价格(您绝不想依赖于产品表以获取超出初始查询时的价格信息。订购)。

这不是非规范化,数据随时间而变化,但您需要历史值,因此您必须在创建记录时存储它,否则您将丢失数据完整性。您不希望您的财务报告突然显示您去年的销售额增加了30%,因为您有价格更新。这不是你卖的东西。