Ars*_*nko 10 schema sql-server-2008 sql-server optimization
在我正在处理的一个项目中,必须跟踪对数据库某些表中行的每次更改以进行进一步审计或回滚。必须很容易找到谁修改了行,从哪个 IP 地址和时间,并且能够恢复以前的版本。
例如 Stack Exchange 使用了类似的东西。当我改变别人的问题时,有可能发现我改变了它,并且回滚了改变。
考虑到我当前的架构与普通业务应用程序具有大致相同的属性(如下),用于将每个更改存储在数据库中的通用技术是什么?
nvarchar(1000)
例如可能有一些,但不是大量的二进制数据,这个直接存储在磁盘上,直接访问,而不是通过 Microsoft SQL filestream
,<tl-博士>
我想过以下案例,但我对这些场景没有真正的经验,所以我想听听其他人的意见:
将所有内容存储在同一个表中,按 ID 和版本区分行。IMO,这是非常愚蠢的,迟早会在性能水平上受到伤害。使用这种方法,也不可能为最新项目和版本跟踪设置不同的安全级别。最后,每个查询的编写都会更加复杂。实际上,要访问最新数据,我将被迫按 ID 对所有内容进行分组,并在每个组中检索最新版本。
将最新版本存储在一个表中,并在每次更改时将过时版本复制到另一个模式中的另一个表中。缺陷是每次我们都会存储每个值,即使它没有改变。设置不变值null
不是一个解决方案,因为我还必须当值更改为跟踪null
或null
。
将最新版本存储在一个表中,并将更改的属性列表及其以前的值存储在另一个表中。这似乎有两个缺陷:最重要的一个是,对同一列中不同类型的先前值进行排序的唯一方法是使用binary(max)
. 第二个是,我相信,在向用户显示以前的版本时,使用这种结构会更加困难。
执行与前两点相同的操作,但将版本存储在单独的数据库中。在性能方面,为了避免通过将以前的版本放在同一数据库中而减慢对最新版本的访问速度可能会很有趣;尽管如此,我认为这是一个过早的优化,只有在有证据表明在同一数据库中拥有旧版本和最新版本是瓶颈时才必须进行优化。
</tl-dr>
¹ 例如,将更改存储到日志文件中是不可接受的,就像对 HTTP 日志所做的那样,并在服务器负载最低的晚上将数据从日志刷新到数据库中。有关不同版本的信息必须立即或几乎立即可用;几秒钟的延迟是可以接受的。
² 信息不是很频繁,只有特定的用户组才能访问,但是,强迫他们等待 30 秒才能显示版本列表是不可接受的。同样,几秒钟的延迟是可以接受的。
进行此类审计日志记录的正常方法是在您正在审计的基表上创建一个影子表并记录更改和触发器。如果出于性能需要,其他表可以放在不同的物理磁盘上,如果需要支持快速检索数据,可以在它们上放置索引。
这些表的结构与您的原始表大致相同,但会有一个日期时间列用于指示更改发生的时间,以及用于指示行是否被插入、更改或删除的标记。可以通过时间戳对版本进行排序。
更改日期可以通过使用默认值 getdate() 使日期时间列不为空来完成;审计用户列将使用默认为 Suser_Sname() 的非空列捕获用户。假设在会话中模拟了实际用户,这将捕获进行更改的用户的身份。
数据库无法知道连接到 Web 服务器的 IP 地址。应用程序必须明确捕获并记录事务的 IP 地址。
如果您有大量要审计的表,您可以使用系统数据字典中的元数据以编程方式生成触发器。
由于以下几个原因,此解决方案是迄今为止最好的:
它捕获对表的任何更改,而不仅仅是应用程序所做的更改。
审计表可以放在一组不同的磁盘上,以减少主表上的 I/O 负载。
您可以使用基于表和审计日志表联合的视图来显示包括当前版本在内的整个历史记录。
您可以根据需要为审计日志表编制索引,以便审计用户可以响应地查询它们。像往常一样,索引选择是查询性能和更新开销之间的权衡。