Projektowanie baz danych do rejestrowania audytów

Za każdym razem, gdy potrzebuję zaprojektować nową bazę danych spędzam sporo czasu zastanawiam się, jak skonfigurować schemat bazy danych, aby prowadzić dziennik audytu zmiany.

Kilka pytań już tu padło, ale nie zgadzam się, że istnieje jedno najlepsze podejście do wszystkich scenariuszy:

Natknąłem się również na ten ciekawy artykuł na temat prowadzenia dziennika zmian w bazie danych, który próbuje wymienić zalety i wady każdego podejścia. Jest bardzo dobrze napisana i zawiera ciekawe informacje, ale jeszcze bardziej utrudniła mi decyzje.

Moje pytanie brzmi: czy jest odniesienie, które mogę użyć, może książka lub coś w rodzaju drzewa decyzyjnego, które mogę odnieść się do zdecydować, w którą stronę powinienem iść na podstawie niektórych zmienne wejściowe, like:

  • dojrzałość schematu bazy danych
  • Jak będą sprawdzane logi
  • prawdopodobieństwo, że będzie trzeba odtworzyć rekordy
  • co jest ważniejsze: wydajność zapisu lub odczytu
  • Charakter wartości, które są rejestrowane (string, numbers, blobs)
  • Dostępna przestrzeń dyskowa

Podejścia, które znam to:

1. Dodaj kolumny dla daty utworzenia i modyfikacji oraz użytkownika

Tabela przykład:

  • id
  • wartość_1
  • wartość_2
  • wartość_3
  • created_date
  • modifed_date
  • created_by
  • modified_by

Główne wady: tracimy historię modyfikacji. Nie można wycofać się po zatwierdzeniu.

2. Wstaw tylko tabele

Przykład tabeli :

  • id
  • wartość_1
  • wartość_2
  • wartość_3
  • od
  • do
  • usunięty (boolean)
  • użytkownik

Główne wady: jak aktualizować klucze obce? Potrzebna ogromna przestrzeń

3. Tworzenie osobnej tabeli historii dla każdej tabeli

Przykład tabeli historii:

  • id
  • wartość_1
  • wartość_2
  • wartość_3
  • wartość_4
  • użytkownik
  • deleted (boolean)
  • timestamp

Główne wady: musi duplikować wszystkie skontrolowane tabele. Jeśli zmieni się schemat będzie potrzebny do migracji wszystkich dzienniki też.

4. Tworzenie skonsolidowanej tabeli historii dla wszystkich tabel

Przykład tabeli historii:

  • table_name
  • pole
  • użytkownik
  • new_value
  • deleted (boolean)
  • timestamp

Główne wady: czy będę w stanie odtworzyć rekordy (rollback) w razie potrzeby łatwo? Kolumna new_value musi być wielkim ciągiem znaków, aby mogła obsługiwać wszystkie typy kolumn.

Author: Community, 2010-01-06

5 answers

Jedną z metod używanych przez kilka platform wiki jest oddzielenie danych identyfikacyjnych od treści, które kontrolujesz. Dodaje to złożoności, ale kończy się to ścieżką audytu kompletnych rekordów, a nie tylko listami pól, które zostały edytowane, które następnie musisz zacierać, aby dać użytkownikowi wyobrażenie, jak wyglądał stary rekord.

Więc na przykład, jeśli masz tabelę o nazwie Opportunities do śledzenia transakcji sprzedaży, w rzeczywistości utworzyłbyś dwa oddzielne tabele:

Możliwości
Opportunities_Content (lub coś w tym stylu)

TabelaOpportunities zawierałaby informacje, których użyłbyś do jednoznacznej identyfikacji rekordu i zawierałaby klucz główny, do którego odwołałbyś się w związku z kluczami obcymi. Tabela Opportunities_Content zawiera wszystkie pola, które użytkownicy mogą zmienić i dla których chcesz zachować ścieżkę audytu. Każdy rekord w tabeli Content będzie zawierał własne PK oraz dane zmodyfikowane według daty i daty modyfikacji. Tabela Opportunities zawiera odniesienie do aktualnej wersji, a także informacje o tym, kiedy i przez kogo został utworzony główny rekord.

Oto prosty przykład:

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

I treści:

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

Prawdopodobnie uczyniłbym PK spisu treści wielokolumnowym kluczem z PageID i Revision pod warunkiem, że Revision jest typem tożsamości. Możesz użyć kolumny rewizji jako FK. Ty następnie wyciągnij skonsolidowany rekord, łącząc się w ten sposób:

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

Tam mogą być jakieś błędy...to jest poza moją głową. To powinno dać ci pomysł na alternatywny wzór.

Josh

 78
Author: Josh Anderson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-21 19:18:48

Jeśli używasz SQL Server 2008, prawdopodobnie powinieneś rozważyć zmianę przechwytywania danych. Jest to nowość na rok 2008 i może zaoszczędzić znaczną ilość pracy.

 11
Author: Randy Minder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-06 18:47:01

Nie znam żadnego odniesienia, ale jestem pewien, że ktoś coś napisał.

Jeśli jednak celem jest po prostu posiadanie zapisu tego, co się stało-najbardziej typowego użycia dziennika audytu-to dlaczego po prostu nie zachować wszystkiego:

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

Prawdopodobnie jest to utrzymywane przez wyzwalacz.

 6
Author: wallyk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-06 18:34:13

Myślę, że nie ma to jak drzewo decyzyjne. Ponieważ niektóre plusy i minusy (lub wymagania) nie są naprawdę policzalne. Jak mierzyć na przykład dojrzałość?

Więc po prostu dostosuj swoje wymagania biznesowe do rejestrowania audytu. Spróbuj przewidzieć, jak te wymagania mogą się zmienić w przyszłości i wygenerować swoje wymagania techniczne. Teraz możesz porównać go do zalet i wad i wybrać właściwą / najlepszą opcję.

I bądź pewny, nie ma znaczenia, jak ty zdecyduj, zawsze będzie ktoś, kto myśli, że podjąłeś złą decyzję. Jednak odrobiłeś swoją pracę domową i uzasadniasz swoją decyzję.

 3
Author: Peter Schuetze,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-06 18:47:56

Stworzymy małą przykładową bazę danych dla aplikacji blogowej. Wymagane są dwie tabele:

blog: przechowuje unikalny identyfikator posta, tytuł, zawartość i usuniętą flagę. audit: przechowuje podstawowy zestaw historycznych zmian z identyfikatorem rekordu, identyfikatorem posta na blogu, typem zmiany (Nowa, Edycja lub usunięcie) oraz datą / godziną tej zmiany. Poniższy SQL tworzy blog i indeksuje usuniętą kolumnę:

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';

Poniższy SQL tworzy tabelę audit. Wszystkie kolumny są indeksowane i klucz obcy jest definiowany do audytu.blog_id blog.id. dlatego, gdy fizycznie usuwamy wpis na blogu, usuwa się również pełną historię audytu.

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
Author: ajit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-24 05:51:37