在我正在从事的项目中,必须跟踪对数据库某些表中行的每次更改,以进行进一步的审核或回滚。必须很容易找到谁修改了该行,从哪个IP地址以及何时修改了该行,并且能够还原以前的版本。
例如,Stack Exchange使用了类似的方法。当我更改其他人的问题时,可能会发现我已更改了该问题,并回滚了所做的更改。
假设我当前的架构具有与普通业务应用程序大致相同的属性(下),那么用于将每个更改存储到数据库中的对象的通用技术是什么?
- 对象的大小相对较小:
nvarchar(1000)
例如,可能会有一些,但不是很大的二进制数据斑点,该斑点直接存储在磁盘上,并且可以直接访问,而不是通过Microsoft SQL访问filestream
, - 数据库负载非常低,整个数据库由服务器上的一个虚拟机处理,
- 对先前版本的访问不必与对最新版本的访问一样快,但仍必须是最新版本¹,而又不能太慢²。
<tl-dr>
我考虑过以下情况,但是我对这种情况没有真正的经验,所以我会听到其他人的意见:
将所有内容存储在同一张表中,按ID和版本区分行。国际海事组织,这是非常愚蠢的,并且迟早会影响性能。使用这种方法,也不可能为最新项目和版本跟踪设置不同的安全级别。最后,每个查询的编写都会更加复杂。实际上,要访问最新数据,我将被迫按ID将所有内容分组并在每个组中检索最新版本。
将最新版本存储在一个表中,并在每次更改时将过时的版本复制到另一个架构中的另一个表中。缺陷在于,即使价值不变,我们每次也会存储每个价值。将不变的值设置
null
为并不是解决方案,因为我还必须跟踪何时将值更改为null
或更改为null
。将最新版本存储在一个表中,将已更改属性及其先前值的列表存储在另一表中。这似乎有两个缺陷:最重要的是,在同一列中对异构类型的先前值进行排序的唯一方法是使用
binary(max)
。第二个是,我认为,在向用户显示以前的版本时,使用这种结构会更加困难。执行与前两点相同的操作,但是将版本存储在单独的数据库中。从性能角度来看,为了避免通过在同一数据库中保留以前的版本来减慢对最新版本的访问,可能会很有趣。仍然,我认为这是一个过早的优化,只有在有证据证明在同一数据库中拥有较旧和最新版本是瓶颈时,才必须进行此优化。
</ tl-dr>
¹例如,将更改存储到日志文件中(就像处理HTTP日志一样),并在服务器负载最低的晚上将数据从日志刷新到数据库中是不可接受的。有关不同版本的信息必须立即可用或几乎立即可用;几秒钟的延迟是可以接受的。
²信息访问频率不是很高,只有特定的用户组才能访问,但是仍然不能强迫他们等待30秒才能显示版本列表。同样,延迟几秒钟是可以接受的。