2012-04-11 87 views
2

我有一个基本的CRUD网络应用程序,人们可以创建文章/编辑它们。我现在想添加修改所有修改历史记录的功能。目前,我有一个文章表,看起来像这样:规范化或反规范化将修订历史存储在RDBMS中?

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

我已经考虑了2个选项来改变我当前的模式,以添加对修订历史的支持。基本思想是任何文章的每一个编辑都会作为记录存储在修订表中。所以文章和修订是一对多的关系。

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

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) 

我正在考虑去第二个选项,因为它会使我的编码更容易(不太复杂,代码行少)。我知道这不是“学术”和“纯粹”,但我个人的感觉是,必须进行额外的连接会伤害代码维护。此外,性能应该更好,因为没有必要完成许多联接。

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

+0

JNK是正确的(虽然没有SQL中的连接优化 - RDBMS是。虽然细节)。对于我们的发票申请,我们有类似的问题,但那里的“历史”表是发票表的精确副本,还有一些附加字段(历史PK,时间戳等)。容易'插入历史选择空,现在(),...,我*发票我'* – Konerak 2012-04-11 19:14:30

回答

5

性能的说法是无稽之谈 - 你做的更少JOIN s,但RDBMS针对JOIN进行了优化。

但是,您可能会从服务器拉出批次以上的以上的数据,而这些数据不能被优化掉。

您还可能有一致性问题。在不同表格中复制同一项目的数据会导致出现不一致的能力。如果修订记录和物品记录对于formatauthor有不同的值?你怎么知道哪一个是正确的? Articles中的content与任何修订版本不匹配会怎么样?

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

+0

谢谢你在这方面脱颖而出。我现在意识到,保持一致性的代码可能最终会成为更多的工作。 – trinth 2012-04-11 20:13:57

+0

CurrentRevision字段是否真的有必要?这意味着每次创建或编辑一篇文章时需要3次调用DB: 1.创建文章 2.参考步骤(1)的文章创建修订版 3.使用步骤(2)的修订版更新article.current_revision – trinth 2012-04-11 20:55:43

+1

@trinth虽然这些人都没有理由需要单独打电话。您可以进行一次调用来插入文章和参考,您只需正确处理代码中的ID值即可。 – JNK 2012-04-11 20:59:17

7

如果你关心你的数据,在“非规范化”的情况下你不会得到更少的代码 - 你必须强制Revision中的最后一行总是匹配Article中的副本。这在并发环境中实际上并不是微不足道的 - 你必须非常仔细地进行锁定!

(如果你选择RevisionArticle不包含相同的副本,那么这是更糟糕的 - 你将不能够依靠DBMS为强制执行Revision主键!)

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

即使您没有这样一个DBMS,也只有在您具有测得的数据的实际数据量后才考虑非规范化。是的,连接可以是昂贵的,但他们贵在你的特定情况?只有测量可以说明。


顺便说一句,可以考虑使用标识关系/自然关键是这样的:

enter image description here

revision_no单调,你在给定的文章添加修改的增长。

Revision PK下面的B-Tree结构使得找到给定文章的最新(或任何!)修订版非常高效。除非您的问题中没有显示备用密钥,否则您也可以使用Revision和(在Oracle下)甚至压缩聚簇索引的前沿,因此重复article_id的空间开销将被废止。

+0

我从你的评论中学到了很多东西,我将会用标准化的选项进行讨论。我选择其他答案作为“解决方案”,不过因为他的建议是我最终使用的。 – trinth 2012-04-12 16:00:16

+1

@trinth注意'Article.CurrentRevision'。据推测,“修订版”已经在某个领域订购了,而最后的修订版可以从该订单自然推断出来。因此,“CurrentRevision”不会向系统引入任何新信息,它只是复制现有的信息 - 它是**冗余**,并且冗余会导致修改异常。你甚至没有从它的存在中获得任何性能优势(在B树中,搜索MAX与搜索具体值一样快)。只有当“最后”和“当前”修订意味着不同的事情时,它的存在才是合理的。 – 2012-04-12 16:26:45