Database design 是否有在数据库中维护历史记录的最佳实践?

Database design 是否有在数据库中维护历史记录的最佳实践?,database-design,Database Design,我不经常做数据库工作,所以这对我来说是完全陌生的领域 我有一个表,其中有一堆用户可以更新的记录。但是,我现在想保留它们的更改历史记录,以防它们想要回滚。在这种情况下,回滚不是db回滚,而是更像是两周后当他们意识到自己犯了错误时进行的恢复更改。区别在于我不能让事务处理完成这项工作 当前做法是使用单独的表,还是仅在当前表中使用一个标志 这是一个小型数据库,5个表,每个表

我不经常做数据库工作,所以这对我来说是完全陌生的领域

我有一个表,其中有一堆用户可以更新的记录。但是,我现在想保留它们的更改历史记录,以防它们想要回滚。在这种情况下,回滚不是db回滚,而是更像是两周后当他们意识到自己犯了错误时进行的恢复更改。区别在于我不能让事务处理完成这项工作

当前做法是使用单独的表,还是仅在当前表中使用一个标志


这是一个小型数据库,5个表,每个表<6列,总共<1000行。

您可以使用时间戳指示记录的创建时间,并使用状态指示器指示记录是否处于“活动”状态

当他们对记录进行更新时,将其副本作为新记录插入(触发器可以使时间戳保持最新),然后将旧记录状态设置为“存档”,将新记录状态设置为“活动”。如果需要,还可以有其他审核字段,如“上次更新的时间戳”、“存档日期”、“未存档日期”(用于回滚时)、“由用户创建”、“由用户上次修改”,。。。如果你想要一个完整的审计历史,你需要一个单独的审计表

回滚就是简单地选择一个版本并将其标记为“活动”,将其他版本标记为“存档”


还有其他更灵活但也更复杂的方案,但您可能不需要它们。

一个选项是让所有表都包含一个ID列和一个VersionNo列。然后,不运行更新,而是插入具有相同ID和递增版本号的新记录

然后,您可以为每个表创建多个视图,这些视图只返回每个ID的最新版本,以使查询更易于管理。

来自此问题

保存版本历史记录的一个简单方法是创建一个基本相同的表(例如带有_version后缀)。这两个表都有一个版本字段,对于主表,每次更新都会增加该字段。版本表将在上有一个复合主键(id,version)

无论何时对实际表进行更新,都会在版本表中插入包含重复数据的新行。每当您想要查找版本历史记录时,您所需要做的就是选择*FROM content\u version,其中id=content\u id按版本排序

如果您使用类似于ORM的东西,它会通过事件侦听器自动为您执行此操作。您可以在这里查看:

最简单的解决方案(取决于您的具体需求)可能是在表中添加一个on update/insert/delete触发器,以便在插入/更新/删除数据时执行额外的日志记录。这样,即使是人工干预db也将被涵盖


查看更多信息。

我们的答案是一个解决方案,另一个是一个审计表,记录更改、更改时间和更改人。这确实是一个方法问题。如果应用程序表的性能非常关键,并且它们可以使用“活动行”方法大量增长,那么审计表就更好了,因为它可以将历史记录与活动内容分开(我希望修复用户错误比“正常”事务要少)。

我建议使用第二个表。一种超级简单的方法是复制每个表的模式,以及一个日期/时间戳列和“ModifiedByUserID”列,这些列将存储原始数据

或者,如果用户不同时修改同一行中的许多记录,则可以通过创建以下模式来节省空间并更好地了解正在发生的情况:

易变的
这种方法怎么样?我有一个带有一些表的关系数据库,并在“堆栈”上构建带有时间戳的记录

例如:假设我创建了
employee表
+
Car表
,在第三个表中,我将记录每次更改(带有日期)时的关系
employee Car
。当然,这应该由GUI支持,我可以从GUI中选择将填充新表的记录的组件(employee和car):

first record employee1 <-> car1 : 01/01/2013
then         employee1  <-> car2: 01/06/2013
首次记录员工1 car1:01/01/2013
然后雇员1 car2:01/06/2013

如果我想知道历史,我就问这张桌子。无需更新任何内容历史记录正在随更改滚动。

复制我喜欢版本无想法。我只是希望它不会对我目前拥有的所有测试用例和代码造成重大重写(因为他们不使用视图),这将导致对所有现有代码的重大重写,因为您将不得不要求当前代码。但是,如果您这样做是因为这是一个视图,并且引用了该视图而不是maintable,那么更改将非常简单。如果可以,最简单的重构方法是更改表的名称,然后将视图命名为表最初的名称。这不会中断任何现有代码,并且只有在您希望回滚某些内容时才针对新表编写代码。触发器是最好的处理方法,因为您永远无法保证数据只会从用户界面更改。我同意这一点。只需将审计信息分开。
first record employee1 <-> car1 : 01/01/2013
then         employee1  <-> car2: 01/06/2013