Datenbankdesign für die Überwachungsprotokollierung

151

Jedes Mal, wenn ich eine neue Datenbank entwerfen muss, denke ich lange darüber nach, wie ich das Datenbankschema einrichten soll, um ein Überwachungsprotokoll der Änderungen zu führen.

Hier wurden bereits einige Fragen dazu gestellt, aber ich stimme nicht zu, dass es für alle Szenarien einen einzigen besten Ansatz gibt:

Ich bin auch auf diesen interessanten Artikel über das Verwalten eines Protokolls von Datenbankänderungen gestoßen , in dem versucht wird, die Vor- und Nachteile jedes Ansatzes aufzulisten. Es ist sehr gut geschrieben und enthält interessante Informationen, aber es hat meine Entscheidungen noch schwieriger gemacht.

Meine Frage ist: Gibt es eine Referenz, die ich verwenden kann, vielleicht ein Buch oder so etwas wie einen Entscheidungsbaum, auf den ich mich beziehen kann, um anhand einiger Eingabevariablen zu entscheiden, welchen Weg ich gehen soll, wie:

  • Die Reife des Datenbankschemas
  • Wie die Protokolle abgefragt werden
  • Die Wahrscheinlichkeit, dass Datensätze neu erstellt werden müssen
  • Was wichtiger ist: Schreib- oder Leseleistung
  • Art der zu protokollierenden Werte (Zeichenfolge, Zahlen, Blobs)
  • Speicherplatz verfügbar

Die Ansätze, die ich kenne, sind:

1. Fügen Sie Spalten für das erstellte und geänderte Datum und den Benutzer hinzu

Tabellenbeispiel:

  • Ich würde
  • value_1
  • value_2
  • value_3
  • Erstellungsdatum
  • modifiziertes_Datum
  • erstellt von
  • geändert durch

Hauptnachteile: Wir verlieren die Geschichte der Änderungen. Rollback nach Commit nicht möglich.

2. Fügen Sie nur Tabellen ein

Tabellenbeispiel :

  • Ich würde
  • value_1
  • value_2
  • value_3
  • von
  • zu
  • gelöscht (Boolean)
  • Benutzer

Hauptnachteile: Wie halte ich Fremdschlüssel auf dem neuesten Stand? Riesiger Platzbedarf

3. Erstellen Sie für jede Tabelle eine separate Verlaufstabelle

Beispiel für eine Verlaufstabelle:

  • Ich würde
  • value_1
  • value_2
  • value_3
  • value_4
  • Benutzer
  • gelöscht (Boolean)
  • Zeitstempel

Hauptnachteile: Muss alle geprüften Tabellen duplizieren. Wenn sich das Schema ändert, müssen auch alle Protokolle migriert werden.

4. Erstellen Sie eine konsolidierte Verlaufstabelle für alle Tabellen

Beispiel für eine Verlaufstabelle:

  • Tabellenname
  • Feld
  • Benutzer
  • neuer Wert
  • gelöscht (Boolean)
  • Zeitstempel

Hauptnachteile: Kann ich die Datensätze bei Bedarf problemlos neu erstellen (Rollback)? Die Spalte new_value muss eine große Zeichenfolge sein, damit alle verschiedenen Spaltentypen unterstützt werden können.

jbochi
quelle
1
und was ist mit einer Verlaufsdatenbank anstelle von Tabellen?
Jowen
Vielleicht könnten Sie das Design von github.com/airblade/paper_trail
zx1986
Ist es eine schlechte Idee, alle (erforderlichen) Abfragen so zu protokollieren, wie sie sind?
Dinushan

Antworten:

87

Eine Methode, die von einigen Wiki-Plattformen verwendet wird, besteht darin, die identifizierenden Daten und den Inhalt, den Sie prüfen, zu trennen. Dies erhöht die Komplexität, aber Sie erhalten einen Prüfpfad mit vollständigen Datensätzen, nicht nur Listen mit bearbeiteten Feldern, die Sie dann mischen müssen, um dem Benutzer eine Vorstellung davon zu geben, wie der alte Datensatz aussah.

Wenn Sie beispielsweise eine Tabelle mit dem Namen " Opportunities" zum Nachverfolgen von Verkaufsabschlüssen hätten, würden Sie tatsächlich zwei separate Tabellen erstellen:

Opportunities
Opportunities_Content (oder so ähnlich)

Die Opportunities- Tabelle enthält Informationen, mit denen Sie den Datensatz eindeutig identifizieren können, und enthält den Primärschlüssel, auf den Sie für Ihre Fremdschlüsselbeziehungen verweisen würden. Die Opportunities_Content- Tabelle enthält alle Felder, die Ihre Benutzer ändern können und für die Sie einen Prüfpfad führen möchten. Jeder Datensatz in der Inhaltstabelle enthält eine eigene PK sowie die Daten für das Änderungs- und das Änderungsdatum. Die Opportunities- Tabelle enthält einen Verweis auf die aktuelle Version sowie Informationen darüber, wann und von wem der Hauptdatensatz ursprünglich erstellt wurde.

Hier ist ein einfaches Beispiel:

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

Und der Inhalt:

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

Ich würde wahrscheinlich die PK des Inhaltsverzeichnisses zu einem mehrspaltigen Schlüssel von PageID und Revision machen, vorausgesetzt, Revision ist ein Identitätstyp. Sie würden die Revisionsspalte als FK verwenden. Sie ziehen dann den konsolidierten Datensatz, indem Sie sich wie folgt anmelden:

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

Es könnte dort oben einige Fehler geben ... das ist mir ein Rätsel. Es sollte Ihnen jedoch eine Vorstellung von einem alternativen Muster geben.

Josh Anderson
quelle
10
In Bezug auf den Audit-Ansatz, aber für die Produktion wird es viel Zeit in Anspruch nehmen, eine separate Audit-Tabelle für jede Tabelle in der Datenbank zu entwickeln, Trigger für jede Tabelle zu schreiben, um Änderungen zu erfassen, und diese in die Audit-Tabelle zu schreiben. Darüber hinaus ist es eine große Herausforderung, einen einzigen Prüfbericht für alle Tabellen zu erstellen, da jede Prüfungstabelle eine andere Struktur aufweist.
Asim-Ishaq
11
Wenn das Schreiben und Verwalten von Skripten für jede Tabelle ein Problem für eine Organisation ist, die eine geprüfte Datenbank verwalten möchte, würde ich natürlich empfehlen, entweder einen erfahrenen DBA oder einen hochflexiblen und sehr erfahrenen Softwareentwickler mit ausreichender Erfahrung beim Erstellen geprüfter Datenbanken einzustellen .
Hardryv
1
Ist es richtig, dass PageContent.PageIDFK zu Page.IDund Page.CurrentRevisionFK zu ist PageContent.Revision? Ist diese Abhängigkeit wirklich kreisförmig?
2
Ich habe abgewählt, da die genannten Alternativen nicht angesprochen werden. Es gibt eine weitere Option, die eine sehr spezifische Lösung für einen ganz bestimmten Anwendungsfall darstellt. Aber ich sehe die Vorzüge des vorgeschlagenen Designs
Acteon
1
Ich kann mir nur sehr wenige Felder vorstellen, von denen ich mit Zuversicht sagen kann, dass sie sich nicht ändern werden, sodass alle "Haupt" -Tabellen für jede Entität nur so sind id, revision_id. Eigentlich eher ein Kreuzungstisch. Das fühlt sich für mich ein bisschen stinkend an. Welchen Vorteil hat dies gegenüber Ansatz 3 in OP (Verlaufstabelle pro geprüfte Tabelle)?
Kenmore
14

Wenn Sie SQL Server 2008 verwenden, sollten Sie wahrscheinlich die Datenerfassung ändern in Betracht ziehen. Dies ist neu für 2008 und könnte Ihnen einen erheblichen Arbeitsaufwand ersparen.

Randy Minder
quelle
Hier ist der Link zu den SQL 2012-Informationen zur Änderungsverfolgung. msdn.microsoft.com/en-us/library/bb933994.aspx +1 für die Verwendung der integrierten Funktionalität, es macht keinen Sinn, das Rad neu zu erfinden.
Chris
4
@ Chris hast du es jemals selbst benutzt? In der Tat verfolgt es alles ... aber in der Lage zu sein, nützliche Informationen daraus zu gewinnen, ist eine ganz andere Geschichte. Ich kann kein Traktorrad für mein Fahrrad verwenden.
Jowen
Das wäre wirklich großartig gewesen. Wenn Sie jedoch wie ich nur die Standard Edition von SQL Server haben, haben Sie kein Glück: "Die Erfassung von Änderungsdaten ist nur in den Editionen Enterprise , Developer und Enterprise Evaluation verfügbar ."
Brad Turek
6

Ich kenne keine Referenz, aber ich bin sicher, dass jemand etwas geschrieben hat.

Wenn der Zweck jedoch einfach darin besteht, aufzuzeichnen, was passiert ist - die typischste Verwendung eines Überwachungsprotokolls -, warum nicht einfach alles aufbewahren:

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

Vermutlich wird dies durch einen Trigger aufrechterhalten.

Wallyk
quelle
Ich kenne keine Möglichkeit, dies innerhalb des Datenbankservers zu erreichen, aber das könnte natürlich von außen leicht genug geschehen.
Wallyk
5
Es scheint mir, dass dies das gleiche Entwurfsmuster ist wie die 4. Option, die in der ursprünglichen Frage gezeigt wurde.
Givanse
3

Wir erstellen eine kleine Beispieldatenbank für eine Blogging-Anwendung. Es sind zwei Tabellen erforderlich:

blog: speichert eine eindeutige Post-ID, den Titel, den Inhalt und eine gelöschte Flagge. audit: speichert einen grundlegenden Satz historischer Änderungen mit einer Datensatz-ID, der Blog-Post-ID, dem Änderungstyp (NEU, BEARBEITEN oder LÖSCHEN) und dem Datum / der Uhrzeit dieser Änderung. Das folgende SQL erstellt die blogund indiziert die gelöschte Spalte:

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

Die folgende SQL erstellt die auditTabelle. Alle Spalten sind indiziert und für audit.blog_id ist ein Fremdschlüssel definiert, der auf blog.id verweist. Wenn wir einen Blogeintrag physisch LÖSCHEN, wird daher auch der vollständige Überwachungsverlauf entfernt.

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;
Ajit
quelle
2

Ich denke, es gibt nichts Schöneres als einen Entscheidungsbaum. Da einige der Vor- und Nachteile (oder die Anforderungen) nicht wirklich abzählbar sind. Wie messen Sie zum Beispiel die Reife?

Richten Sie einfach Ihre Geschäftsanforderungen für Ihre Überwachungsprotokollierung aus. Versuchen Sie vorherzusagen, wie sich diese Anforderungen in Zukunft ändern werden, und generieren Sie Ihre technischen Anforderungen. Jetzt können Sie es mit den Vor- und Nachteilen vergleichen und die richtige / beste Option auswählen.

Und seien Sie versichert, es spielt keine Rolle, wie Sie sich entscheiden, es wird immer jemanden geben, der glaubt, Sie hätten die falsche Entscheidung getroffen. Sie haben jedoch Ihre Hausaufgaben gemacht und Ihre Entscheidung begründet.

Peter Schuetze
quelle