对于我的应用程序中的实体,我计划记录常见的元数据,如DateCreated,DateModified,IPAddress等。在实体表中添加这些列是否有意义,或者更好的是有一个表用于记录元数据-data,其中每一行都链接回它对应的项目?稍后为了报告和分析,我可以创建所需的视图。
答案 0 :(得分:1)
如果您只想保留最新信息(如最近修改的时间和IP地址),请将其放在表格中。如果您想要更像审计日志的内容,您可以在其中查看所有历史更改,那么它应该位于单独的表中。
答案 1 :(得分:1)
我使用一个特殊的查询,将所有这些公共列(我称之为审计列)添加到所有表(使用游标遍历信息模式),这样可以很容易地将它们应用到新数据库。
我的列是(特定于SQL Server):
RowId UNIQUEIDENTIFIER NOT NULL DEFAULT (NEWID()), Created DATETIME NOT NULL DEFAULT (GETDATE()), Creator NVARCHAR(256) NOT NULL DEFAULT(SUSER_SNAME()) RowStamp TIMESTAMP NOT NULL
现在,在完全规范化的模式中,我只需要RowId
,它将链接到包含其他行的Audit表。事实上,经过反思,我几乎希望自己走下这条路 - 主要是因为它使表格变得丑陋(事实上我将这些列留在数据库架构图中)。
但是,在处理非常大的数据集时,您可以通过在表格中使用这些数据来提高性能,而且到目前为止我还没有遇到过这个系统的任何问题。
编辑也可以发布代码以添加审核列:
DECLARE AuditCursor CURSOR FOR SELECT TABLE_SCHEMA, TABLE_NAME from INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND OBJECTPROPERTY(OBJECT_ID(QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME)), 'IsMSShipped') = 0 AND TABLE_NAME NOT IN ('sysdiagrams') AND TABLE_NAME NOT LIKE 'dt_%' -- NB: you could change the above to only do it for certain tables OPEN AuditCursor DECLARE @schema varchar(128), @table varchar(128) FETCH NEXT FROM AuditCursor INTO @schema, @table WHILE @@FETCH_STATUS -1 BEGIN PRINT '* Adding audit columns to [' + @schema + '].[' + @table + ']...' IF NOT EXISTS (SELECT NULL FROM information_schema.columns WHERE table_schema = @schema AND table_name = @table AND column_name = 'Created') BEGIN DECLARE @sql_created varchar(max) SELECT @sql_created = 'ALTER TABLE [' + @schema + '].[' + @table + '] ADD [Created] DATETIME NOT NULL CONSTRAINT [DF_' + @table + '_Created] DEFAULT (GETDATE())' EXEC ( @sql_created ) PRINT ' - Added Created' END ELSE PRINT ' - Created already exists, skipping' IF NOT EXISTS (SELECT NULL FROM information_schema.columns WHERE table_schema = @schema AND table_name = @table AND column_name = 'Creator') BEGIN DECLARE @sql_creator varchar(max) SELECT @sql_creator = 'ALTER TABLE [' + @schema + '].[' + @table + '] ADD [Creator] VARCHAR(256) NOT NULL CONSTRAINT [DF_' + @table + '_Creator] DEFAULT (SUSER_SNAME())' EXEC ( @sql_creator ) PRINT ' - Added Creator' END ELSE PRINT ' - Creator already exists, skipping' IF NOT EXISTS (SELECT NULL FROM information_schema.columns WHERE table_schema = @schema AND table_name = @table AND column_name = 'RowId') BEGIN DECLARE @sql_rowid varchar(max) SELECT @sql_rowid = 'ALTER TABLE [' + @schema + '].[' + @table + '] ADD [RowId] UNIQUEIDENTIFIER NOT NULL CONSTRAINT [DF_' + @table + '_RowId] DEFAULT (NEWID())' EXEC ( @sql_rowid ) PRINT ' - Added RowId' END ELSE PRINT ' - RowId already exists, skipping' IF NOT EXISTS (SELECT NULL FROM information_schema.columns WHERE table_schema = @schema AND table_name = @table AND (column_name = 'RowStamp' OR data_type = 'timestamp')) BEGIN DECLARE @sql_rowstamp varchar(max) SELECT @sql_rowstamp = 'ALTER TABLE [' + @schema + '].[' + @table + '] ADD [RowStamp] ROWVERSION NOT NULL' EXEC ( @sql_rowstamp ) PRINT ' - Added RowStamp' END ELSE PRINT ' - RowStamp or another timestamp already exists, skipping' -- basic tamper protection against non-SA users PRINT ' - setting DENY permission on audit columns' DECLARE @sql_deny VARCHAR(1000) SELECT @sql_deny = 'DENY UPDATE ON [' + @schema + '].[' + @table + '] ([Created]) TO [public]' + 'DENY UPDATE ON [' + @schema + '].[' + @table + '] ([RowId]) TO [public]' + 'DENY UPDATE ON [' + @schema + '].[' + @table + '] ([Creator]) TO [public]' EXEC (@sql_deny) PRINT '* Completed processing [' + @schema + '].[' + @table + ']' FETCH NEXT FROM AuditCursor INTO @schema, @table END CLOSE AuditCursor DEALLOCATE AuditCursor GO
答案 2 :(得分:0)
这是一个关于您是否应该规范化数据库的经典问题。我会说你应该规范化,只有在你需要它时才能去标准化(性能等)。