每次我需要设计一个新数据库时,我都会花一些时间 考虑如何设置数据库模式以保持审计日志 变化。
这里已经有人提出了一些问题,但我不同意 对于所有场景,都有一种最佳方法:
我也偶然发现了interesting article on Maintaining a Log of Database Changes试图列出每种方法的利弊。它编写得很好并且有很多有趣的信息,但它使我的决定更加艰难。
我的问题是:是否有我可以使用的参考资料,可能是一本书或类似决策树的东西我可以参考决定我应该以哪种方式为基础 输入变量,如:
我所知道的方法是:
1。添加创建和修改日期和用户的列
表示例:
主要缺点:我们失去了修改的历史。提交后无法回滚。
2。仅插入表格
主要缺点:如何保持外键最新?需要巨大的空间
第3。为每个表创建一个单独的历史记录表
历史表示例:
主要缺点:需要复制所有审计表。如果架构发生更改,则还需要迁移所有日志。
4。为所有表格创建合并历史记录表
历史表示例:
主要缺点:如果需要,我能否轻松地重新创建记录(回滚)? new_value列需要是一个巨大的字符串,因此它可以支持所有不同的列类型。
答案 0 :(得分:80)
一些wiki平台使用的一种方法是将识别数据与您正在审核的内容分开。它增加了复杂性,但您最终得到了完整记录的审计跟踪,而不仅仅是已编辑的字段列表,您必须将其混搭以便让用户了解旧记录的外观。
例如,如果您有一个名为机会的表来跟踪销售交易,您实际上会创建两个单独的表:
<强>有机会强>
机会_内容(或类似内容)
机会表将包含您用于唯一标识记录的信息,并包含您为外键关系引用的主键。 Opportunities_Content 表将包含您的用户可以更改的所有字段以及您希望保留审计跟踪的字段。 内容表中的每条记录都包含自己的PK以及修改日期和修改日期数据。 机会表格将包含对当前版本的引用,以及有关何时最初创建主记录以及由谁创建的信息。
这是一个简单的例子:
CREATE TABLE dbo.Page(
ID int PRIMARY KEY,
Name nvarchar(200) NOT NULL,
CreatedByName nvarchar(100) NOT NULL,
CurrentRevision int NOT NULL,
CreatedDateTime datetime NOT NULL
内容:
CREATE TABLE dbo.PageContent(
PageID int NOT NULL,
Revision int NOT NULL,
Title nvarchar(200) NOT NULL,
User nvarchar(100) NOT NULL,
LastModified datetime NOT NULL,
Comment nvarchar(300) NULL,
Content nvarchar(max) NOT NULL,
Description nvarchar(200) NULL
我可能会使内容表的PK成为PageID和Revision提供的多列密钥,并且Revision是一种身份类型。您可以使用“修订”列作为FK。然后通过JOINing拉出合并记录:
SELECT * FROM Page
JOIN PageContent ON CurrentRevision = Revision AND ID = PageID
那里可能有一些错误......这是我的头脑。不过,它应该让你了解另一种模式。
答案 1 :(得分:13)
如果您使用的是SQL Server 2008,则可能应考虑更改数据捕获。这是2008年的新功能,可以为您节省大量的工作。
答案 2 :(得分:6)
我不知道有任何参考,但我确信有人写了一些东西。
但是,如果目的只是记录发生的事情 - 最常见的审计日志使用 - 那么为什么不简单地保留所有内容:
timestamp
username
ip_address
procedureName (if called from a stored procedure)
database
table
field
accesstype (insert, delete, modify)
oldvalue
newvalue
据推测,这是由触发器维持的。
答案 3 :(得分:3)
我们将为博客应用程序创建一个小型示例数据库。需要两个表:
blog
:存储唯一的帖子ID,标题,内容和已删除的标记。
audit
:存储一组基本的历史更改,包括记录ID,博客帖子ID,更改类型(NEW,EDIT或DELETE)以及更改的日期/时间。
以下SQL创建blog
并为已删除的列编制索引:
CREATE TABLE `blog` (
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`title` text,
`content` text,
`deleted` tinyint(1) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `ix_deleted` (`deleted`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='Blog posts';
以下SQL创建audit
表。索引所有列,并为audit.blog_id定义外键,引用blog.id.因此,当我们实际删除博客条目时,它的完整审核历史记录也会被删除。
CREATE TABLE `audit` (
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`blog_id` mediumint(8) unsigned NOT NULL,
`changetype` enum('NEW','EDIT','DELETE') NOT NULL,
`changetime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `ix_blog_id` (`blog_id`),
KEY `ix_changetype` (`changetype`),
KEY `ix_changetime` (`changetime`),
CONSTRAINT `FK_audit_blog_id` FOREIGN KEY (`blog_id`) REFERENCES `blog` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
答案 4 :(得分:2)
我认为没有像决策树那样的东西。由于一些优点和缺点(或要求)不是真的可数。例如,你如何衡量成熟度?
因此,请列出审计日志记录的业务要求。尝试预测未来这些要求可能会如何变化并产生您的技术要求。现在,您可以将其与优缺点进行比较,并选择正确/最佳选项。
请放心,无论你如何决定,都会有人认为你做出了错误的决定。但是,你做了功课,你证明了你的决定。
答案 5 :(得分:0)
我正在使用以下结构:
id int
user_id int
system_user_id int
tenant_id int
db_name varchar
model_name varchar
model_primary_key int
model_attributes text
created_at timestamp
ip varchar
session_id varchar
request_id varchar
comments text
目前运行良好,支持约 3.62 亿条记录、多租户、多数据库。
model_attributes 是最重要的,改变了什么,作为键值格式的json字符串。