如何版本控制数据库中的记录

Nie*_*sma 158 architecture database-design

假设我在数据库中有一条记录,管理员和普通用户都可以进行更新.

任何人都可以建议一个好的方法/架构如何版本控制此表中的每个更改,以便可以将记录回滚到以前的版本.

WW.*_*WW. 154

假设您有一个FOO管理员和用户可以更新的表.大多数情况下,您可以针对FOO表编写查询.快乐的时光.

然后,我会创建一个FOO_HISTORY表.这包含FOO表格的所有列.主键与FOO和RevisionNumber列相同.有从外键FOO_HISTORYFOO.您还可以添加与修订相关的列,例如UserId和RevisionDate.在所有*_HISTORY表中(即从Oracle序列或等效表)中以不断增加的方式填充RevisionNumbers .不要依赖于那里只在一秒钟内进行一次更改(即不要放入RevisionDate主键).

现在,每次更新时FOO,就在进行更新之前,将旧值插入FOO_HISTORY.您可以在设计的某个基础级别执行此操作,以便程序员不会意外地错过此步骤.

如果你想从中删除一行,FOO你有一些选择.级联和删除所有历史记录,或通过标记FOO为已删除来执行逻辑删除.

当您对当前值感兴趣并且仅偶尔在历史中感兴趣时,此解决方案很好.如果您总是需要历史记录,那么您可以设置有效的开始和结束日期并保留所有记录FOO.然后每个查询都需要检查这些日期.

  • 我woyuld建议您实际插入_new_数据,而不是之前的数据,因此历史表包含所有数据.虽然它存储了redyundent数据,但它消除了在需要历史数据时处理两个表中的搜索所需的特殊情况. (37认同)
  • 就个人而言,我建议不要删除任何内容(将其推迟到特定的内务活动)并使用"操作类型"列来指定是否插入/更新/删除.对于删除,您可以正常复制行,但在"操作类型"列中添加"删除". (6认同)
  • @Hydrargyrum保存当前值的表将比历史表的视图表现更好.您可能还希望定义引用当前值的外键. (3认同)
  • `有一个从FOO_HISTORY到FOO'的外键:坏主意,我想删除foo中的记录而不改变历史记录.历史表应该在正常使用时只插入. (2认同)

CMS*_*CMS 41

我认为您正在寻找版本化数据库记录的内容(正如StackOverflow在有人编辑问题/答案时所做的那样).一个好的起点可能是看一些使用修订跟踪的数据库模型.

想到的最好的例子是维基百科引擎MediaWiki.比较这里的数据库图,特别是修订表.

根据您使用的技术,您必须找到一些好的差异/合并算法.

检查这个问题是否适用于.NET.


Dav*_*ley 27

在BI世界中,您可以通过向要版本的表添加startDate和endDate来实现此目的.将第一条记录插入表中时,将填充startDate,但endDate为null.插入第二条记录时,还会使用第二条记录的startDate更新第一条记录的endDate.

如果要查看当前记录,请选择endDate为null的记录.

这有时被称为类型2 慢慢变化的维度.另见TupleVersioning

  • 是的,但是您可以通过对表进行索引和/或分区来处理这个问题。此外,只会有一小部分大桌子。大多数都会小得多。 (2认同)

D3v*_*r0n 9

升级到SQL 2008.

尝试在SQL 2008中使用SQL更改跟踪.您可以使用此新功能跟踪数据库中数据的更改,而不是使用时间戳和逻辑删除列黑客.

MSDN SQL 2008更改跟踪


wuh*_*her 6

只是想补充说,这个问题的一个好方法是使用Temporal数据库.许多数据库供应商都提供开箱即用或扩展的功能.我已成功使用PostgreSQL 的临时表扩展,但其他人也使用它.每当更新数据库中的记录时,数据库也会保留该记录的先前版本.


alo*_*lok 5

两种选择:

  1. 有一个历史表 - 每当更新原始数据时,将旧数据插入此历史记录表.
  2. 审计表 - 存储前后值 - 仅适用于审计表中的已修改列以及其他信息,例如更新者和何时更新.


Rei*_*ica 5

您可以通过 SQL 触发器对 SQL 表执行审计。您可以从触发器访问 2 个特殊表(插入和删除)。这些表包含每次更新表时插入或删除的确切行。在触发器 SQL 中,您可以将这些修改后的行插入到审计表中。这种方法意味着你的审计对程序员是透明的;不需要他们的努力或任何实施知识。

这种方法的额外好处是,无论 sql 操作是通过您的数据访问 DLL 还是通过手动 SQL 查询,都会进行审计;(因为审计是在服务器本身上执行的)。


小智 5

AlokAudit table上面建议的,我想在我的帖子中解释一下。

我在我的项目中采用了这种无模式的单表设计。

架构:

  • id - 整数自动递增
  • 用户名 - STRING
  • 表名 - STRING
  • 旧值 - 文本/JSON
  • 新值 - 文本/JSON
  • 创建于 - 日期时间

该表可以将每个表的历史记录全部保存在一个位置,并将完整的对象历史记录保存在一条记录中。该表可以使用数据更改的触发器/挂钩来填充,存储目标行的旧值和新值快照。

这种设计的优点:

  • 历史管理需要管理的表数量更少。
  • 存储每行旧状态和新状态的完整快照。
  • 方便在每张桌子上进行搜索。
  • 可以按表创建分区。
  • 可以定义每个表的数据保留策略。

这种设计的缺点:

  • 如果系统变化频繁,数据量可能会很大。