关于捕获审计跟踪的数据库设计的想法

Gre*_*ens 41 database audit database-design

如何在数据库中维护数据日志?

我必须记录每行所做的每个更改.这意味着我不能允许DELETEUPDATE执行.

我怎么能保留这样的日志?

Shi*_*iji 24

使用"仅插入数据库"

基本思想是您永远不会更新或删除数据.

每个表都有2分datetime列.

它们以每个值的null值开始(从时间开始到结束时间)

当你需要"改变"你添加一个新行的行,同时您更新前一行到现在和该行中要添加到现在.

您通过视图中的数据从表中读取数据,其中where = null.

此方法还可以为您提供任何时间点数据库状态的图片.

编辑

只是为了澄清以回应评论:序列将由表的主键给出,这将是一个自动增量数.

  • 如果您需要数据,如果需要审计跟踪,则可以使用数据,但不会浪费. (19认同)
  • Kolten,如果你在一个行业中工作,由于监管合规你必须跟踪所有事情,你会发现这是一个必要的邪恶.此外,海报只能审核他/她最感兴趣的表格子集,因此空间浪费与他/她想要的记录水平有关... (6认同)
  • 对于任何ID /搜索数据或任何序列数据,我都不会使用日期时间列.系统日期可能因任何原因而改变,或者在同一时间内发生多个操作,单个日期/时间值的分辨率都是可能的.如果你需要及时捕获序列使用时间戳(保证唯一)或使用长整数或使用guid,因为你也建立了一个链(但你作为一个信息项失去了时间 - 也读下面的答案......) (4认同)
  • 这不仅仅是浪费太多空间吗? (2认同)
  • 我以前在特定表格中使用过这种模式.我建议使用由外键和'to'值组成的唯一索引.这意味着在更新上一个当前记录的to字段之前不能插入另一行. (2认同)
  • 不要同时存储`to`和`from`,它会引入更新异常 - 这是不正确的设计.您只需要存储一个值. (2认同)
  • 您如何通过此设计处理引用完整性?由于主键列将不再是行对象实例的静态 ID,因此给定对象现在将有许多行(对于每个版本或更改)(如果您明白我的意思) (2认同)

小智 17

[后期帖子,但它增加了两种未在此处提及的技术]

读取事务日志 - 如果数据库处于完全恢复模式,则事务日志会存储许多可用于查看每行历史记录的有用信息.缺点是默认情况下不支持此功能.您可以尝试使用未记录的函数DBCC LOG或fn_dblog或第三方工具(如ApexSQL Log)

使用更改数据捕获 - 更改数据捕获基本上与上面显示的相同,但它更简化,更容易使用.不幸的是,这仅适用于企业版.

这两者都可以解决允许更新和删除的问题,因为您无法真正更改事务日志中的内容.


Pau*_*ier 14

如Shiraz Bhaji所述,使用"仅插入"数据库,但您可以使用更简单的技术.对于您需要维护审计数据的每个表,只需要有一个更新时间的附加列,默认为现在.当您对记录进行更改而不是更新时,只需插入所有数据; UpdatedTime列将获取当前时间.

请注意,此方法意味着您必须打破或重新考虑您的UNIQUE约束; 您可以保留主键,但唯一性将成为主键和UpdatedTime的组合.

这种技术的优点是可以为表中的每条记录提供一个已知范围的历史数据(如果它是记录的TOP 1,则每条记录在有效时间内有效,其中TimeOfInterest> UpdatedTime ORDER BY UpdatedTime DESC),开销较低(桌子上只有一列).它也非常适合从不使用此方法的表进行转换,使用简单的ALTER TABLE添加单个列(您可以一致地命名).然后,您只需要更改UNIQUE约束以使用其当前约束和UpdatedTime列的组合,并且需要更改某些查询.

还要注意,如果您创建一个只返回每条记录的最新条目的表视图,您实际上可以避免转换所有查询; 最终得到一个透明地维护历史数据的表,以及一个看起来像没有更改记录的常规表的视图.


Dav*_*ave 5

一种完全不同的方法是只有一个审计日志.然后,您可以使用它来构建最新版本的数据.您可以定期创建"检查点"或使用缓存来加快速度.

有关使用此技术的人的介绍:http://www.infoq.com/presentations/greg-young-unshackle-qcon08.这里的一大优势是,由于您只有审计日志,因此您将非常确信您的审计跟踪是正确的.

我从来没有试过这个,看起来很复杂......但要考虑一些事情.