我需要创建一个数据库表来存储不同的变更日志/审计(添加、删除、修改等内容时)。我不需要存储特别详细的信息,所以我在想一些事情:
- id(用于事件)
- 触发它的用户
- 事件名称
- 事件描述
- 事件的时间戳
我在这里错过了什么吗?显然,我可以继续改进设计,尽管我不打算让它变得复杂(为事件类型或类似的东西创建其他表是不可能的,因为这对我的需要来说很复杂)。
我需要创建一个数据库表来存储不同的变更日志/审计(添加、删除、修改等内容时)。我不需要存储特别详细的信息,所以我在想一些事情:
我在这里错过了什么吗?显然,我可以继续改进设计,尽管我不打算让它变得复杂(为事件类型或类似的东西创建其他表是不可能的,因为这对我的需要来说很复杂)。
在我正在做的项目中,审计日志也是从非常简约的设计开始的,就像你描述的那样:
event ID
event date/time
event type
user ID
description
这个想法是一样的:让事情变得简单。
然而,很快就发现这种简约的设计是不够的。典型的审计归结为这样的问题:
Who the heck created/updated/deleted a record
with ID=X in the table Foo and when?
因此,为了能够快速回答此类问题(使用 SQL),我们最终在审计表中增加了两列
object type (or table name)
object ID
那是我们审计日志的设计真正稳定的时候(现在已经有几年了)。
当然,最后的“改进”仅适用于具有代理键的表。但猜猜怎么了?我们所有值得审计的表都有这样的密钥!
我们还记录旧值和新值以及它们来自的列以及在审计详细信息表中被审计的表的主键。想想你需要审计表做什么?您不仅想知道谁进行了更改以及何时进行了更改,而且当发生错误更改时,您还需要一种快速恢复数据的方法。
在设计时,您应该编写代码来恢复数据。当您需要恢复时,通常会很匆忙,最好已经做好准备。
您可能还需要审核其他几项内容,例如表/列名称、从中进行更新的计算机/应用程序等等。
现在,这取决于您真正需要的审计详细程度以及级别。
我们开始构建自己的基于触发器的审计解决方案,我们希望审计所有内容,并且手头还有一个恢复选项。事实证明这太复杂了,因此我们最终对基于触发器的第三方工具ApexSQL Audit进行了逆向工程,以创建我们自己的自定义解决方案。
尖端:
包括之前/之后的值
包括 3-4 列用于存储主键(如果它是复合键)
按照 Robert 的建议,将数据存储在主数据库之外
花大量时间准备报告——尤其是那些你可能需要恢复的报告
计划存储主机/应用程序名称——这对于跟踪可疑活动可能非常有用
这里和类似的问题中有很多有趣的答案。我可以从个人经验中添加的唯一内容是:
将您的审计表放在另一个数据库中。理想情况下,您希望与原始数据分离。如果您需要恢复您的数据库,您并不想恢复审计跟踪。
尽可能合理地去规范化。您希望表对原始数据具有尽可能少的依赖关系。审计表应该简单且快速地从中检索数据。无需跨其他表进行花哨的连接或查找来获取数据。
一般来说,自定义审计(创建各种表)是一个不好的选择。可以禁用数据库/表触发器以跳过一些日志活动。自定义审计表可以被篡改。可能会发生导致应用程序中断的异常情况。更不用说设计一个健壮的解决方案的困难了。到目前为止,我在这个讨论中看到了一个非常简单的案例。您需要与当前数据库和任何特权用户(DBA、开发人员)完全分离。每个主流的 RDBMS 都提供审计设施,即使是 DBA 也无法禁用、秘密篡改。因此,RDBMS 供应商提供的审计能力必须是第一选择。其他选项是 3rd 方事务日志阅读器或自定义日志阅读器,它们将分解的信息推送到消息系统中,最终以某种形式的审计数据仓库或实时事件处理程序结束。总之:解决方案架构师/“Hands on Data Architect”需要参与根据需求确定这样的系统。通常只是交给开发人员解决问题太严重了。
有很多方法可以做到这一点。我最喜欢的方式是:
将一个mod_user
字段添加到您的源表(您要记录的那个)。
创建一个日志表,其中包含要记录的字段以及一个log_datetime
和seq_num
字段。 seq_num
是主键。
在源表上构建一个触发器,只要任何受监控的字段发生更改,就将当前记录插入到日志表中。
现在,您已经记录了每一次更改以及是谁做出的。
我们的桌子上有什么:-
Primary Key
Event type (e.g. "UPDATED", "APPROVED")
Description ("Frisbar was added to blong")
User Id
User Id of second authoriser
Amount
Date/time
Generic Id
Table Name
通用 id 指向表中已更新的一行,表名是该表的字符串名称。不是一个好的数据库设计,但非常有用。我们所有的表都有一个代理键列,所以这很好用。
根据分离原理:
审计数据表需要与主数据库分开。因为审计数据库可能有大量历史数据,所以从内存利用率的角度来看,将它们分开是有意义的。
不要使用触发器来审计整个数据库,因为你最终会得到一堆不同的数据库来支持。您必须为 DB2、SQLServer、Mysql 等编写一个。