Дизайн бази даних для проведення аудиту аудиту


151

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

Тут вже були задані деякі питання, але я не згоден, що існує найкращий підхід для всіх сценаріїв:

Я також натрапив на цю цікаву статтю про ведення журналу змін бази даних, яка намагається перелічити плюси та мінуси кожного підходу. Це дуже добре написано і має цікаву інформацію, але це зробило мої рішення ще важче.

Моє запитання: чи є посилання, яке я можу використати, можливо, книга чи щось на зразок дерева рішень, яке я можу посилати, щоб вирішити, яким шляхом слід піти на основі деяких вхідних змінних, наприклад:

  • Зрілість схеми бази даних
  • Як запитуватимуть журнали
  • Ймовірність того, що знадобиться відтворити записи
  • Що важливіше: виконання або запис читання
  • Характер значень, що реєструються (рядок, числа, крапки)
  • Вільне місце для зберігання

Мені відомі підходи:

1. Додайте стовпці для створених та змінених дат та користувачів

Приклад таблиці:

  • ід
  • значення_1
  • значення_2
  • значення_3
  • created_date
  • модифіковано_даними
  • створено
  • модифікований_by

Основні мінуси: Ми втрачаємо історію модифікацій. Неможливо відкатати після фіксації.

2. Вставте лише таблиці

Приклад таблиці :

  • ід
  • значення_1
  • значення_2
  • значення_3
  • з
  • до
  • видалено (булева)
  • користувач

Основні мінуси: Як оновлювати зовнішні ключі? Потрібно величезний простір

3. Створіть окрему таблицю історії для кожної таблиці

Приклад таблиці історії:

  • ід
  • значення_1
  • значення_2
  • значення_3
  • значення_4
  • користувач
  • видалено (булева)
  • мітка часу

Основні мінуси: Необхідно дублювати всі перевірені таблиці. Якщо схема зміниться, знадобиться і для переміщення всіх журналів.

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

Приклад таблиці історії:

  • Таблиця_ім'я
  • поле
  • користувач
  • new_value
  • видалено (булева)
  • мітка часу

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



1
а як щодо використання бази даних історії замість таблиць?
Джовен

Можливо, ви можете перевірити дизайн github.com/airblade/paper_trail
zx1986

Це погана ідея реєструвати всі (обов’язкові) запити, виконані як є?
Дінушан

Відповіді:


87

Один із методів, який використовується декількома платформами вікі - це розділити ідентифікаційні дані та вміст, який ви ревізуєте. Це додає складності, але ви закінчуєте аудиторський слід повних записів, а не лише списки полів, які були відредаговані, а потім вам доведеться розминати, щоб дати користувачеві уявлення про те, як виглядала стара запис.

Так, наприклад, якби у вас була таблиця під назвою " Можливості відстежувати угоди з продажу", ви б створили дві окремі таблиці:

Можливості
Можливості_Контент (або щось подібне)

У таблиці " Можливості" буде інформація, яку ви б використали для унікальної ідентифікації запису і містив би основний ключ, на який ви посилаєтесь, для своїх зовнішніх ключових зв'язків. У таблиці Opportunities_Content містяться всі поля, які можуть змінити ваші користувачі, і для яких ви хочете зберегти аудиторський слід. Кожен запис у таблиці Вміст міститиме власну ПК та дані, що модифікуються та модифікуються. Таблиця можливостей міститиме посилання на поточну версію, а також інформацію про те, коли головна запис була створена спочатку і ким.

Ось простий приклад:

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

Я, мабуть, зробить ПК таблиці вмісту багатоколонним ключем від PageID та Revision за умови, що Ревізія була типом ідентичності. Ви б використовували стовпець "Ревізія" як FK. Потім витягуєте консолідований запис, приєднавшись так:

SELECT * FROM Page
JOIN PageContent ON CurrentRevision = Revision AND ID = PageID

Можливо, там є якісь помилки ... це вгорі голови. Однак це повинно дати вам уявлення про альтернативний зразок.


10
Що стосується хорошого підходу до аудиту, але для виробництва знадобиться багато часу, щоб розробити окрему таблицю аудиту для кожної таблиці в базі даних, записати тригери для кожної таблиці для фіксації змін та записування її до таблиці аудиту. Крім того, величезна проблема у розробці єдиного аудиторського звіту для всіх таблиць, оскільки кожна таблиця аудиту відрізняється за структурою.
asim-ishaq

11
Якщо написання та підтримка сценаріїв для кожної таблиці викликає занепокоєння для організації, яка має намір керувати ревізованою базою даних, я, звичайно, рекомендую найняти або досвідченого DBA, або надзвичайно гнучкого та дуже досвідченого програмного інженера, що має достатній досвід створення ревізованих баз даних .
Хардрів

1
Чи правильно PageContent.PageIDце ФК Page.IDі Page.CurrentRevisionФК PageContent.Revision? Чи справді ця залежність кругла?

2
Я проголосував, оскільки він не стосується згаданих альтернатив. Це дає ще один варіант, який є дуже конкретним рішенням дуже конкретного випадку використання. Але я бачу достоїнства запропонованого дизайну
acteon

1
Я можу подумати про дуже небагато полів, про які я можу з упевненістю сказати, що не зміниться, тому всі "основні" таблиці для кожної організації закінчуються просто " id, revision_id; більше, наприклад, розв'язковий стіл. Мені це здається трохи смердючим. Яку перевагу має це у порівнянні з підходом 3 в ОП (таблиця історії за аудированою таблицею)?
Кенмор

14

Якщо ви використовуєте SQL Server 2008, ви, мабуть, повинні врахувати Змінити захоплення даних. Це нове для 2008 року і може заощадити значну кількість роботи.


ось посилання на інформацію про відстеження змін у SQL 2012. msdn.microsoft.com/en-us/library/bb933994.aspx +1 для використання вбудованої функціональності, не має сенсу повторно винаходити колесо.
Кріс

4
@Chris Ви коли-небудь використовували його самостійно? Справді, він відстежує все ... але вміти отримувати корисну інформацію з нього - це зовсім інша історія. Не можу використовувати колесо трактора для мого велосипеда.
Джовен

Це справді було б дивним. Але якщо у вас є лише стандартне видання SQL Server, як я, вам не пощастило: "Зміна захоплення даних доступна лише у виданнях Enterprise , Developer та Enterprise Evaluation ".
Бред Турек

6

Я не знаю жодної посилання, але я впевнений, що хтось щось написав.

Однак, якщо мета полягає в тому, щоб просто мати запис про те, що сталося - найбільш типове використання журналу аудиту - то чому б просто не зберегти все:

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

Імовірно, це підтримується тригером.


Я не знаю жодного способу отримати це на сервері баз даних, але, звичайно, це можна зробити ззовні досить легко.
wallyk

5
Мені здається, що це та сама модель дизайну, що і 4-й варіант, показаний в оригінальному запитанні.
givanse

3

Ми створимо невелику прикладну базу даних для програми для ведення блогів. Потрібні дві таблиці:

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

Я думаю, що немає нічого подібного до дерева рішень. Оскільки деякі плюси і мінуси (або вимоги) насправді не піддаються обліку. Як Ви, наприклад, вимірюєте зрілість?

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

І будьте впевнені, неважливо, як ви вирішите, завжди знайдеться хтось, хто вважає, що ви прийняли неправильне рішення. Однак ви зробили домашнє завдання і ви виправдовуєте своє рішення.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.