规范化或非规范化以在RDBMS中存储修订历史记录?

时间:2012-04-11 19:06:48

标签: sql database-design schema rdbms

我有一个基本的CRUD网络应用程序,人们可以在其中创建文章/编辑它们。我现在想要添加保留所有编辑的修订历史记录的功能。目前,我有一个看起来像这样的文章表:

Article(id, title, content, author_id, category_id, format)

我考虑了两个用于更改当前架构的选项,以添加对修订历史记录的支持。基本思路是将任何文章的每个编辑都存储为修订表中的记录。所以文章和修订是一对多的关系。

第一个选项(标准化): 一个用于文章元数据的表,一个用于修订。没有存储重复数据。

Article(id, title, category_id)
Revision(id, content, author_id, format)

第二个选项(去标准化): 两个表,如选项1,但有一些重复的列。

Article(id, title, content, author_id, category_id, format)
Revision(id, article_id, content, author_id, format)

我正在考虑使用第二个选项,因为它会使我的编码更容易(更简单,更少的代码行)。我知道它不是“学术性的”和“纯粹的”但我个人的感觉是,不得不做额外的连接会损害代码维护。此外,性能应该更好,因为不必进行很多连接。

这是完成此任务的合理方式吗?可能是我忽略的任何不可预见的或长期的后果?

2 个答案:

答案 0 :(得分:7)

如果您关心自己的数据,那么“非规范化”案例中的代码不会少 - 您必须强制Revision中的最新行始终与Article中的副本匹配。这在并发环境中实际上是微不足道的 - 你必须非常小心地进行锁定!

(如果您选择RevisionArticle不包含相同的副本,那么情况会更糟 - 您将无法依赖DBMS来强制执行{{1主键!)

使用足够强大的DBMS,您可以拥有自己的蛋糕并吃掉它 - 例如,Oracle物化视图可以为您“预加入”数据,而无需对实际数据模型进行非规范化。

即使您没有这样的DBMS,只有在测量在实际数据量上的性能之后,才考虑进行非规范化。是的,JOINS可能很贵,但是在你的特殊情况下它们是否太贵了?只有测量才能证明。


顺便说一下,考虑使用这样的识别关系/自然键:

enter image description here

Revision在给定文章下添加修订版时单调增长。

revision_no PK下面的B树结构使得查找给定文章的最新(或任何!)修订版非常有效。除非您的问题中没有显示备用密钥,否则您还可以cluster Revision和(在Oracle下)甚至压缩聚类索引的前沿,因此重复Revision的空间开销被取消。

答案 1 :(得分:5)

性能参数是无意义的 - 您执行的JOIN更少,但RDBMS针对JOIN进行了优化。

但是,您可能会从服务器中提取批次更多数据,而这些数据无法进行优化。

您还可能遇到一致性问题。在不同表中复制相同项目的数据会导致出现不一致的情况。如果修订记录和文章记录对formatauthor有不同的值,该怎么办?你怎么知道哪个是正确的?如果content中的Articles与任何修订都不匹配,该怎么办?

你真的应该正常化这个。我会在CurrentRevision表中添加Articles字段以链接到当前版本,并且ArticleID表中应该有一个Revisions来将两者链接在一起。< / p>