我有一个基本的 CRUD 网络应用程序,人们可以在其中创建文章/编辑它们。我现在想添加保留所有编辑的修订历史的功能。目前,我有一个如下所示的文章表:
Article(id, title, content, author_id, category_id, format)
我考虑了 2 个选项来更改我当前的架构以添加对修订历史记录的支持。基本思想是对任何文章的每一次编辑都作为一条记录存储在修订表中。所以 Articles 和 Revisions 是一对多的关系。
第一个选项(规范化): 一张表用于文章元数据,一张用于修订。没有存储重复数据。
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)
我正在考虑使用第二个选项,因为它会使我的编码更容易(不那么复杂,代码行数更少)。我知道这不是“学术”和“纯粹”的,但我个人的感觉是必须进行额外的连接会损害代码维护。此外,性能应该更好,因为不必完成那么多的连接。
这是完成这项任务的合理方法吗?我可能忽略了任何不可预见的或长期的后果?
最佳答案
如果你关心你的数据,你不会在“非规范化”的情况下以更少的代码结束 - 你必须强制 Revision
中的最新行始终与 中的副本匹配>文章
。这在并发环境中实际上远非微不足道 - 您必须非常小心地进行锁定!
(如果您选择 Revision
和 Article
不包含相同的副本,那么情况更糟 - 您将无法依赖 DBMS用于强制执行 Revision
主键!)
有了足够强大的 DBMS,您就可以吃蛋糕和吃它了 - 例如,Oracle 实体化 View 可以为您“预连接”数据,而无需对实际数据模型进行非规范化。
即使您没有这样的 DBMS,也只有在您测量实际数据量的性能后才考虑反规范化。是的,JOINS 可能很昂贵,但在您的特定情况下它们太昂贵了吗?只有测量才能告诉我们。
顺便说一句,考虑像这样使用识别关系/自然键:
revision_no
随着您在给定文章下添加修订而单调增长。
Revision
PK 下的 B-Tree 结构使得查找给定文章的最新(或任何!)修订版变得非常高效。除非您的问题中没有显示备用键,否则您也可以 cluster Revision
和(在 Oracle 下)甚至压缩了集群索引的前沿,因此重复 article_id
的空间开销被取消了。
关于sql - 规范化或非规范化以在 RDBMS 中存储修订历史?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10112322/