Проектирование базы данных для ведения журнала аудита - PullRequest
138 голосов
/ 06 января 2010

Каждый раз, когда мне нужно спроектировать новую базу данных, я трачу довольно много времени думать о том, как мне настроить схему базы данных, чтобы вести журнал аудита изменения.

Некоторые вопросы уже задавались здесь по этому поводу, но я не согласен с этим Для всех сценариев существует единый наилучший подход:

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

Мой вопрос: Есть ли ссылка, которую я могу использовать, может быть, книга или что-то вроде дерева решений, на которое я могу сослаться, чтобы решить, каким путем я должен идти, основываясь на некоторых входные переменные, такие как:

  • Срок действия схемы базы данных
  • Как будут запрашиваться журналы
  • Вероятность того, что понадобится воссоздать записи
  • Что важнее: производительность записи или чтения
  • Характер регистрируемых значений (строки, числа, капли)
  • Доступно место для хранения

Подходы, которые я знаю:

1. Добавить столбцы для созданной и измененной даты и пользователя

Пример таблицы:

  • значение_1
  • значение_2
  • VALUE_3
  • created_date
  • MODIFIED_DATE
  • CREATED_BY
  • MODIFIED_BY

Основные минусы: Мы теряем историю модификаций. Невозможно выполнить откат после коммита.

2. Вставьте только таблицы

Пример таблицы :

  • ID
  • значение_1
  • значение_2
  • VALUE_3
  • от
  • до
  • удалено (логическое значение)
  • Пользователь * * 1092

Основные минусы: как поддерживать актуальность внешних ключей? Требуется огромное пространство

3. Создайте отдельную таблицу истории для каждой таблицы

Пример таблицы истории:

  • ID
  • значение_1
  • значение_2
  • VALUE_3
  • value_4
  • Пользователь
  • удалено (логическое значение)
  • 1118 * Отметка времени *

Основные минусы: необходимо дублировать все проверенные таблицы. Если схема изменится, потребуется перенести и все журналы.

4. Создать сводную таблицу истории для всех таблиц

Пример таблицы истории:

  • table_name
  • поле
  • Пользователь
  • удалено (логическое значение)
  • Отметка времени

Основные минусы: Смогу ли я легко воссоздать записи (откат), если нужно? Столбец new_value должен быть огромной строкой, чтобы он мог поддерживать все типы столбцов.

Ответы [ 5 ]

80 голосов
/ 07 января 2010

Один метод, который используется несколькими вики-платформами, заключается в разделении идентифицирующих данных и контента, который вы проверяете. Это добавляет сложности, но в итоге вы получаете контрольный журнал с полными записями, а не просто списки полей, которые были отредактированы, и которые вам нужно будет затем объединить, чтобы дать пользователю представление о том, как выглядела старая запись.

Так, например, если у вас есть таблица с именем Возможности для отслеживания сделок продажи, вы фактически создадите две отдельные таблицы:

Возможность
Opportunities_Content (или что-то в этом роде)

Таблица Opportunities будет содержать информацию, которую вы будете использовать для уникальной идентификации записи, и будет содержать первичный ключ, на который вы будете ссылаться для ваших отношений с внешним ключом. Таблица Opportunities_Content будет содержать все поля, которые могут изменить ваши пользователи и для которых вы хотите вести контрольный журнал. Каждая запись в таблице Content будет содержать свой собственный PK и данные с изменениями и датами изменения. Таблица Opportunities будет содержать ссылку на текущую версию, а также информацию о том, когда основная запись была создана и кем.

Вот простой пример:

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

Там могут быть некоторые ошибки ... это не в моей голове. Это должно дать вам представление об альтернативном паттерне.

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

Если вы используете SQL Server 2008, вам, вероятно, следует рассмотреть возможность сбора данных об изменении. Это новое для 2008 года и может сэкономить значительный объем работы.

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

Я не знаю ни одной ссылки, но я уверен, что кто-то что-то написал.

Однако, если цель состоит в том, чтобы просто получить отчет о том, что произошло - наиболее типичное использование журнала аудита - тогда почему бы просто не сохранить все:

timestamp
username
ip_address
procedureName (if called from a stored procedure)
database
table
field
accesstype (insert, delete, modify)
oldvalue
newvalue

Предположительно, это поддерживается триггером.

3 голосов
/ 24 апреля 2015

Мы создадим небольшую базу данных для блогового приложения. Требуются две таблицы:

blog: хранит уникальный идентификатор сообщения, заголовок, контент и удаленный флаг. audit: хранит базовый набор исторических изменений с идентификатором записи, идентификатором сообщения в блоге, типом изменения (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. Все столбцы проиндексированы, а внешний ключ определен для audit.blog_id, который ссылается на 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;
2 голосов
/ 06 января 2010

Я думаю, что нет ничего лучше, чем дерево решений. Так как некоторые плюсы и минусы (или требования) на самом деле не учитываются. Как вы измеряете зрелость, например?

Так что просто выровняйте свои бизнес-требования для ведения журнала аудита. Постарайтесь предсказать, как эти требования могут измениться в будущем, и сформируйте свои технические требования. Теперь вы можете сравнить его с плюсами и минусами и выбрать правильный / лучший вариант.

И будьте уверены, не имеет значения, как вы решите, всегда найдется кто-то, кто думает, что вы приняли неправильное решение. Тем не менее, вы сделали свою домашнюю работу и оправдываете свое решение.

...