每次我需要设计一个新的数据库时,我都会花很多时间思考如何设置数据库模式以保留更改的审核日志。
这里已经提出了一些问题,但我不同意所有场景都有一个最佳方法:
Database Design For Revisions Best design for a change log auditing database table Ideas on database design for capturing audit trails我也偶然发现了这个interesting article on Maintaining a Log of Database Changes,它试图列出每种方法的优缺点。它写得很好,有有趣的信息,但它使我的决定更加困难。
我的问题是:是否有一个我可以使用的参考,也许是一本书或类似决策树的东西,我可以参考根据一些输入变量来决定我应该走哪条路,例如:
数据库模式的成熟度
如何查询日志
需要重新创建记录的概率
更重要的是:写入或读取性能
正在记录的值的性质(字符串、数字、 blob)
可用存储空间
我知道的方法是:
1.为创建和修改的日期和用户添加列
表示例:
id
value_1
value_2
value_3
created_date
modified_date
created_by
modified_by
主要缺点:我们丢失了修改的历史记录。提交后无法回滚。
2.仅插入表
Table example:id
value_1
value_2
value_3
从
到
已删除 (布尔值)
用户
主要缺点:如何保持外键最新?需要巨大的空间
3.为每个表创建一个单独的历史记录表
历史记录表示例:
id
value_1
value_2
value_3
value_4
用户
已删除 (布尔值)
时间戳
主要缺点:需要复制所有审计表。如果架构更改,则还需要迁移所有日志。
4.为所有表创建合并历史记录表
历史记录表示例:
table_name
字段
用户
new_value
已删除 (布尔值)
时间戳
主要缺点:如果需要,我可以轻松地重新创建记录(回滚)吗?new_value 列需要是一个巨大的字符串,以便它可以支持所有不同的列类型。
一些 wiki 平台使用的一种方法是将识别数据和您正在审核的内容分开。它增加了复杂性,但您最终会得到完整记录的审核跟踪,而不仅仅是编辑过的字段列表,然后您必须将其混在一起才能让用户了解旧记录的样子。
例如,如果您有一个名为Opportunities的表来跟踪销售交易,您实际上会创建两个单独的表:
机会
机会内容(或类似的东西)
Opportunities表中有您用来唯一标识记录的信息,并将包含您为外键关系引用的主键。Opportunities_Content表将包含您的用户可以更改的所有字段,您希望为其保留审计跟踪。Content表中的每个记录都将包含其自己的 PK,以及 a 作为当前修改日期
下面是一个简单的例子:
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 是身份类型。您将使用 Revision 列作为 FK。然后,您可以通过如下方式连接来提取合并记录:
SELECT * FROM Page
JOIN PageContent ON CurrentRevision = Revision AND ID = PageID
上面可能有一些错误...这是我的头顶。不过,它应该给你一个替代模式的想法。
如果您使用的是 SQL Server 2008,您可能应该考虑更改数据捕获。这是 2008 年的新功能,可以节省大量工作。
我不知道任何参考,但我相信有人写了一些东西。
但是,如果目的仅仅是记录发生的事情-审计日志的最典型用途-那么为什么不简单地保留所有内容:
timestamp
username
ip_address
procedureName (if called from a stored procedure)
database
table
field
accesstype (insert, delete, modify)
oldvalue
newvalue
大概这是由触发器维持的。
我们将为博客应用程序创建一个小型示例数据库。需要两个表:
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
表。所有列都被索引,并且为引用 blog.id 的 audit.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;
本站系公益性非盈利分享网址,本文来自用户投稿,不代表边看边学立场,如若转载,请注明出处
评论列表(12条)