2010-01-06 78 views
0

对于我的应用程序中的实体,我打算记录像DateCreated,DateModified,IPAddress等通用元数据。在实体表中添加这些列是否有意义,还是最好有一个表来记录meta-数据中每一行都链接回它对应的项目?稍后为了报告和分析的目的,我可以创建所需的观点。将元数据记录为实体表的一部分还是单独的?

回答

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,这将链接到含有其他行的审核表。事实上,经过反思,我几乎希望我走下了这条路 - 主要是因为它使表格变得丑陋(实际上我把这些列从数据库模式图中排除)。

但是,当处理非常大的数据集时,您可以通过在表中使用这些数据来提高性能,并且迄今为止我还没有遇到过这个系统的任何问题。

编辑:不妨张贴代码添加审计列:

 
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 
1

如果您只想保留最新信息(如最后一次修改时间和IP地址),请将其放在表格中。如果你想要更像审计日志的东西,在那里你可以看到所有的历史变化,那么它应该在一个单独的表格中。

0

这是一个关于是否应该规范化数据库的经典问题。我会说,你应该正常化,并且只有在你需要时才会去规范化(性能等)。

相关问题