将元数据记录为实体表的一部分还是分开?

时间:2010-01-06 19:15:17

标签: mysql database logging database-design split

对于我的应用程序中的实体,我计划记录常见的元数据,如DateCreated,DateModified,IPAddress等。在实体表中添加这些列是否有意义,或者更好的是有一个表用于记录元数据-data,其中每一行都链接回它对应的项目?稍后为了报告和分析,我可以创建所需的视图。

3 个答案:

答案 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)

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