通常如何存储数据库中行的每次更改的记录?


10

在我正在从事的项目中,必须跟踪数据库某些表中行的每次更改,以进行进一步的审核或回滚。必须很容易找到谁修改了该行,从哪个IP地址以及何时修改了该行,并且能够还原以前的版本。

例如,Stack Exchange使用了类似的方法。当我更改其他人的问题时,可能会发现我已更改了该问题,并回滚了所做的更改。

假设我当前的架构具有与普通业务应用程序大致相同的属性(下),那么用于将每个更改存储到数据库中的对象的通用技术是什么

  • 对象的大小相对较小:nvarchar(1000)例如,可能会有一些,但不是很大的二进制数据斑点,该斑点直接存储在磁盘上,并且可以直接访问,而不是通过Microsoft SQL访问filestream
  • 数据库负载非常低,整个数据库由服务器上的一个虚拟机处理,
  • 对先前版本的访问不必与对最新版本的访问一样快,但仍必须是最新版本¹,而又不能太慢²。

<tl-dr>

我考虑过以下情况,但是我对这种情况没有真正的经验,所以我会听到其他人的意见:

  1. 将所有内容存储在同一张表中,按ID和版本区分行。国际海事组织,这是非常愚蠢的,并且迟早会影响性能。使用这种方法,也不可能为最新项目和版本跟踪设置不同的安全级别。最后,每个查询的编写都会更加复杂。实际上,要访问最新数据,我将被迫按ID将所有内容分组并在每个组中检索最新版本。

  2. 将最新版本存储在一个表中,并在每次更改时将过时的版本复制到另一个架构中的另一个表中。缺陷在于,即使价值不变,我们每次也会存储每个价值。将不变的值设置null为并不是解决方案,因为我还必须跟踪何时将值更改为null或更改为null

  3. 将最新版本存储在一个表中,将已更改属性及其先前值的列表存储在另一表中。这似乎有两个缺陷:最重要的是,在同一列中对异构类型的先前值进行排序的唯一方法是使用binary(max)。第二个是,我认为,在向用户显示以前的版本时,使用这种结构会更加困难。

  4. 执行与前两点相同的操作,但是将版本存储在单独的数据库中。从性能角度来看,为了避免通过在同一数据库中保留以前的版本来减慢对最新版本的访问,可能会很有趣。仍然,我认为这是一个过早的优化,只有在有证据证明在同一数据库中拥有较旧和最新版本是瓶颈时,才必须进行此优化。

</ tl-dr>


¹例如,将更改存储到日志文件中(就像处理HTTP日志一样),并在服务器负载最低的晚上将数据从日志刷新到数据库中是不可接受的。有关不同版本的信息必须立即可用或几乎立即可用;几秒钟的延迟是可以接受的。

²信息访问频率不是很高,只有特定的用户组才能访问,但是仍然不能强迫他们等待30秒才能显示版本列表。同样,延迟几秒钟是可以接受的。


3
相关:SQL Server 更改数据捕获
Nick Chammas

Answers:


8

进行此类审计日志记录的通常方法是拥有一个影子表,并在要审计的基表上记录带有触发器的更改。如果需要提高性能,可以将其他表放在不同的物理磁盘上,如果需要支持快速检索数据,则可以在它们上放置索引。

这些表将具有与原始表大致相同的结构,但将具有一个datetime列(用于指示更改发生的时间)和一个用于标记该行是插入,更改还是删除的标记。可以通过时间戳对版本进行排序。

可以通过使datetime列不为null并使用默认值getdate()来完成更改日期。审核用户列将使用默认为Suser_Sname()的非空列来捕获用户。假设在会话中模拟了实际用户,这将捕获进行更改的用户的身份。

数据库无法知道连接到Web服务器的IP地址。该应用程序将必须显式捕获事务并记录IP地址。

如果您要审核的表数量很多,则可以使用系统数据字典中的元数据以编程方式生成触发器。

迄今为止,由于以下几个原因,此解决方案是最好的:

  • 它捕获对表的任何更改,而不仅仅是应用程序所做的更改。

  • 审核表可以放在另一组磁盘上,以减少主表上的I / O负载。

  • 您可以使用基于表和审核日志表的并集的视图,以显示整个历史记录,包括当前版本。

  • 您可以根据需要索引审核日志表,以便审核用户可以响应性地查询它们。通常,索引选择是查询性能和更新开销之间的折衷。


您尝试说如果我有1000个表,我需要维护任何更改的日志,那么我必须创建1000个影子表,是吗?和1000个触发器以捕获更改?如果是的话,那是虚假的主意...我们可以创建一个历史记录表和一个触发器来捕获和记录更改的数据。我们可以将旧行和新行数据以xml格式存储在该表中。...很多人都这样做。
Thomas

1
对于1000个表,您编写了一个实用程序,该实用程序将从系统数据字典中读取定义,并生成触发器和表定义。我已经在具有560个表的系统上完成了它,并且工作得很好。
ConcernedOfTunbridgeWells 2014年

0

我知道许多使用单个表存储数据所有版本的CMS系统(包括Wordpress)。但是再说一次,他们只需要对具有博客文章的表执行此操作。请参阅Wordpress数据库结构

另外,记录的数量和每行经过的修订的数量将在您的决策中发挥重要作用。


0

关于CMS版本控制;对于drupal,它为存储旧值的实体的每个字段创建一个特殊的表;这样的概念允许您对数据进行精细的操作,但是我认为这很昂贵,我自己的解决方案是将我的对象转换为xml格式,并与其他字段(changetime,id ...)存储为字符串

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.