Регистрировать метаданные как часть таблиц сущностей или как отдельные? - PullRequest
0 голосов
/ 06 января 2010

Для сущностей в моем приложении я планирую регистрировать общие метаданные, такие как DateCreated, DateModified, IPAddress и т. Д. Имеет ли смысл добавлять эти столбцы в таблицы сущностей или лучше иметь одну таблицу для регистрации метаданных -данные, где каждая строка имеет ссылку на элемент, которому она соответствует? Позже с целью составления отчетов и анализа я могу создать нужные представления.

Ответы [ 3 ]

1 голос
/ 06 января 2010

Я использую специальный запрос, который добавляет все эти общие столбцы (я называю их столбцами аудита) ко всем таблицам (используя курсор, перемещающийся по информационной схеме), что позволяет легко применять их к новым базам данных.

Мои столбцы (специфичные для 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 голос
/ 06 января 2010

Если вы хотите сохранить только самую последнюю информацию (как в последний раз, когда она была изменена и по какому IP-адресу), поместите ее прямо в таблицу.Если вам нужно что-то более похожее на журнал аудита, где вы можете увидеть все исторические изменения, тогда это должно быть в отдельной таблице.

0 голосов
/ 06 января 2010

Это классический вопрос о том, следует ли нормализовать базу данных или нет. Я бы сказал, что вы должны нормализовать и только нормализовать, если вам это нужно (производительность и т. Д.).

...