Bestes Design für eine Changelog / Auditing-Datenbanktabelle? [geschlossen]

114

Ich muss eine Datenbanktabelle erstellen, um verschiedene Änderungsprotokolle / -überwachungen zu speichern (wenn etwas hinzugefügt, gelöscht, geändert usw. wurde). Ich muss keine besonders detaillierten Informationen speichern, daher habe ich mir Folgendes überlegt:

  • id (für event)
  • Benutzer, der es ausgelöst hat
  • Veranstaltungsname
  • Eventbeschreibung
  • Zeitstempel der Veranstaltung

Vermisse ich hier etwas? Natürlich kann ich das Design weiter verbessern, obwohl ich nicht vorhabe, es kompliziert zu machen (das Erstellen anderer Tabellen für Ereignistypen oder ähnliches kommt nicht in Frage, da dies eine Komplikation für meine Bedürfnisse darstellt).

rcphq
quelle
Ich habe Ihre Antwort gelesen und bin überrascht, dass niemand über das Gesetz spricht. Ich weiß, dass einige Gesetze oder gute Praxisdokumente erklären, wie wir eine (schreibgeschützte) Audittabelle implementieren MÜSSEN. Aber ich habe nicht mehr Informationen als diese. Ich weiß nur, dass es existiert. Ich denke an Audit Trail in CFR 21 Teil 11.
Bastien Vandamme

Antworten:

69

In dem Projekt, an dem ich arbeite, begann das Audit-Protokoll auch mit dem sehr minimalistischen Design, wie dem von Ihnen beschriebenen:

event ID
event date/time
event type
user ID
description

Die Idee war dieselbe: die Dinge einfach zu halten.

Es wurde jedoch schnell klar, dass dieses minimalistische Design nicht ausreichte. Das typische Audit bestand aus folgenden Fragen:

Who the heck created/updated/deleted a record 
with ID=X in the table Foo and when?

Um solche Fragen schnell beantworten zu können (mit SQL), hatten wir zwei zusätzliche Spalten in der Prüftabelle

object type (or table name)
object ID

Zu diesem Zeitpunkt hat sich das Design unseres Audit-Protokolls wirklich stabilisiert (seit einigen Jahren).

Natürlich würde die letzte "Verbesserung" nur für Tabellen funktionieren, die Ersatzschlüssel hatten. Aber rate mal was? Alle unsere prüfenswerten Tabellen haben einen solchen Schlüssel!

Yarik
quelle
Das einzige Problem, das ich mit diesem Design hatte (ein auf einer Beschreibung basierender Prüfpfad), ist die Lokalisierung der in diesem Bereich verwendeten Sprache.
Sam Wilson
@Sam Ich sehe ein solches Problem nicht. Wenn die Nachricht vom System generiert wurde, verwenden Sie hier einfach einen Schlüssel für die Übersetzungszeichenfolge.
JCM
4
@Hiru: Wenn Sie zwei oder mehr unterschiedliche Konzepte in einer Spalte "mischen", wird es früher oder später meistens nach hinten losgehen. Wenn Sie beispielsweise Ereignistyp und Objekttyp "mischen", wirkt sich dies auf Abfragen wie "Datensätze für alle Objekte des angegebenen Typs anzeigen" und "Datensätze für alle Ereignisse eines bestimmten Typs anzeigen" aus (die Abfragen wären mehr) kompliziert und würde höchstwahrscheinlich viel langsamer arbeiten).
Yarik
3
Zusätzlich zu diesen Spalten kann eine zusätzliche Spalte für die strukturierte Beschreibung / strukturierte Ereignisnutzlast vorhanden sein . Diese Spalte enthält Ereignisdetails (unabhängig von ihrer Komplexität) in einem computerlesbaren Format, XML / JSON. Einfach zu serialisieren, abzufragen (zumindest in Postgres / MSSQL), zu überlegen.
Turdus-Merula
1
@ Benjamin: Die Antwort liegt im Domain-Modell (auch bekannt als Geschäftsmodell). Wenn das Modell die gleichzeitige Erstellung von Entitäten ermöglicht (z. B. als Teil einer logischen Transaktion), sehe ich kein Problem darin, mehrere Protokolldatensätze mit genau demselben Zeitstempel zu haben. Wenn beispielsweise die Erstellung einer Bestellung (als Transaktion) die Erstellung von N Bestellpositionen umfassen kann, haben alle entsprechenden 1 + N Protokollsätze denselben Zeitstempel. Eine nachfolgende Analyse eines solchen Protokolls könnte dies ausnutzen und diese 1 + N-Datensätze nicht als unabhängige, sondern als Elemente einer logischen Transaktion behandeln. Hoffe das macht Sinn.
Yarik
24

Wir protokollieren auch alte und neue Werte und die Spalte, aus der sie stammen, sowie den Primärschlüssel der zu prüfenden Tabelle in einer Prüfdetailtabelle. Überlegen Sie, wofür Sie die Audit-Tabelle benötigen? Sie möchten nicht nur wissen, wer wann eine Änderung vorgenommen hat, sondern auch, wenn eine fehlerhafte Änderung eintritt, möchten Sie die Daten schnell zurücksetzen.

Während des Entwurfs sollten Sie den Code schreiben, um Daten wiederherzustellen. Wenn Sie sich erholen müssen, ist es normalerweise eilig, am besten bereits vorbereitet zu sein.

HLGEM
quelle
1
Das ist wirklich gut. Ich verstehe nicht, warum die Leute die letzten Beiträge ignorieren.
Maddy.Shik
3
Event Sourcing ist ein alternativer Ansatz zur Bereitstellung von Rollback-Funktionen unter Beibehaltung des Verlaufs.
Sam
23

Möglicherweise möchten Sie noch einige weitere Dinge überwachen, z. B. Tabellen- / Spaltennamen, Computer / Anwendung, von der aus ein Update durchgeführt wurde, und vieles mehr.

Dies hängt nun davon ab, wie detailliert die Prüfung wirklich ist und auf welcher Ebene.

Wir haben mit dem Aufbau unserer eigenen Trigger-basierten Auditing-Lösung begonnen. Wir wollten alles auditieren und haben auch eine Wiederherstellungsoption zur Hand. Dies stellte sich als zu komplex heraus, sodass wir das Trigger-basierte Drittanbieter-Tool ApexSQL Audit rückentwickelten , um unsere eigene benutzerdefinierte Lösung zu erstellen.

Tipps:

  • Vorher / Nachher-Werte einschließen

  • Fügen Sie 3-4 Spalten zum Speichern des Primärschlüssels hinzu (falls es sich um einen zusammengesetzten Schlüssel handelt).

  • Speichern Sie Daten außerhalb der Hauptdatenbank, wie bereits von Robert vorgeschlagen

  • Nehmen Sie sich ausreichend Zeit für die Erstellung von Berichten - insbesondere für Berichte, die Sie möglicherweise für die Wiederherstellung benötigen

  • Planen Sie das Speichern des Host- / Anwendungsnamens - dies kann sehr nützlich sein, um verdächtige Aktivitäten zu verfolgen

Kenneth Hampton
quelle
2
Warum sollten Sie es zurückentwickeln, anstatt es zu kaufen?
Jowen
1
mehr Kontrolle über das Produkt
Tebe
1
Ich hoffe, sie haben dich nicht verklagt.
Sortierer
9

Hier und in ähnlichen Fragen gibt es viele interessante Antworten. Die einzigen Dinge, die ich aus persönlicher Erfahrung hinzufügen kann, sind:

  1. Stellen Sie Ihre Prüftabelle in eine andere Datenbank. Idealerweise möchten Sie von den Originaldaten getrennt werden. Wenn Sie Ihre Datenbank wiederherstellen müssen, möchten Sie den Audit-Trail nicht wirklich wiederherstellen.

  2. Denormalisieren Sie so viel wie möglich. Sie möchten, dass die Tabelle so wenig Abhängigkeiten wie möglich von den Originaldaten aufweist. Die Audit-Tabelle sollte einfach und blitzschnell sein, um Daten abzurufen. Keine ausgefallenen Verknüpfungen oder Suchvorgänge in anderen Tabellen, um an die Daten zu gelangen.

Robert4Real
quelle
8
Wären nicht normalisierte Daten wirklich schneller zu lesen als normalisierte Daten mit geeigneten Indizes? (Würden nicht alle Duplikate dazu führen, dass mehr Daten von der Festplatte gelesen werden?)
Sam
4

Was wir in unserer Tabelle haben: -

Primary Key
Event type (e.g. "UPDATED", "APPROVED")
Description ("Frisbar was added to blong")
User Id
User Id of second authoriser
Amount
Date/time
Generic Id
Table Name

Die generische ID zeigt auf eine Zeile in der Tabelle, die aktualisiert wurde, und der Tabellenname ist der Name dieser Tabelle als Zeichenfolge. Kein gutes DB-Design, aber sehr brauchbar. Alle unsere Tabellen haben eine einzige Ersatzschlüsselspalte, sodass dies gut funktioniert.

WW.
quelle
2
Was bedeutet "Betrag"?
Turdus-Merula
Es ist eine finanzielle Anwendung, also der Dollarwert der autorisierten Sache usw.
WW.
4

Im Allgemeinen ist eine benutzerdefinierte Prüfung (Erstellen verschiedener Tabellen) eine schlechte Option. Datenbank- / Tabellenauslöser können deaktiviert werden, um einige Protokollaktivitäten zu überspringen. Benutzerdefinierte Prüftabellen können manipuliert werden. Es können Ausnahmen auftreten, die die Anwendung beeinträchtigen. Ganz zu schweigen von Schwierigkeiten beim Entwerfen einer robusten Lösung. Bisher sehe ich in dieser Diskussion sehr einfache Fälle. Sie benötigen eine vollständige Trennung von der aktuellen Datenbank und von allen privilegierten Benutzern (DBA, Entwickler). Alle gängigen RDBMS bieten Prüffunktionen, die selbst der DBA nicht deaktivieren kann, um die Geheimhaltung zu manipulieren. Daher muss die vom RDBMS-Anbieter bereitgestellte Überwachungsfunktion die erste Option sein. Eine andere Option wäre ein Transaktionsprotokollleser eines Drittanbieters oder ein benutzerdefinierter Protokollleser, der zerlegte Informationen in ein Nachrichtensystem überträgt, das in einigen Formen von Audit Data Warehouse oder Echtzeit-Ereignishandler landet. Zusammenfassend: Solution Architect / "Hands on Data Architect" muss ein solches System basierend auf den Anforderungen bestimmen. Es ist normalerweise zu ernst, um es einem Entwickler zur Lösung zu übergeben.

Joel Mamedov
quelle
3

Es gibt viele Möglichkeiten, dies zu tun. Mein Lieblingsweg ist:

  1. Fügen Sie mod_userIhrer Quelltabelle ein Feld hinzu (das, das Sie protokollieren möchten).

  2. Erstellen Sie eine Protokolltabelle, die die zu protokollierenden Felder sowie ein log_datetimeund ein seq_numFeld enthält. seq_numist der Primärschlüssel.

  3. Erstellen Sie einen Trigger für die Quelltabelle, der den aktuellen Datensatz in die Protokolltabelle einfügt, wenn ein überwachtes Feld geändert wird.

Jetzt haben Sie eine Aufzeichnung über jede Änderung und wer sie vorgenommen hat.

JosephStyons
quelle
Also ... was soll das Feld mod_user tun?
Conny
1
Sagen Sie, wer die Änderung vorgenommen hat. Das Aktualisieren des Codes sollte etwas enthalten, um dieses Feld auf den aktuellen Benutzer festzulegen.
JosephStyons
Was ist dann mit Löschen? Wie gehen Sie mit dem Wert für die Spalte mod_user um, wenn Sie eine Zeile löschen?
Kenn Cal
@ KennCal-Trigger können virtuelle Tabellen verwenden. Sie können die Daten nach und vor demselben Trigger anzeigen. Die Operation spielt keine Rolle. stackoverflow.com/questions/6282618/…
Renan Cavalieri
2
@KennCal Sie haben Recht, der Löschauslöser muss diese Informationen entweder für Sie speichern. Der Teufel steckt jedoch im Detail - wenn Sie die SQL-Authentifizierung verwenden, kann der Trigger einfach ausgeführt werden [wählen Sie CURRENT_USER]. Wenn es sich um eine Clientanwendung handelt, muss der Clientcode angeben, wer es ist. Wenn es sich um einen API-Aufruf handelt, muss der löschende Benutzer ein erforderlicher Parameter für den Aufruf sein.
JosephStyons
1

Nach dem Prinzip der Trennung:

  1. Überwachungsdatentabellen müssen von der Hauptdatenbank getrennt sein. Da Überwachungsdatenbanken viele historische Daten enthalten können, ist es unter dem Gesichtspunkt der Speicherauslastung sinnvoll, diese getrennt zu halten.

  2. Verwenden Sie keine Trigger, um die gesamte Datenbank zu überwachen, da Sie am Ende ein Durcheinander verschiedener zu unterstützender Datenbanken haben. Sie müssen eine für DB2, SQLServer, MySQL usw. schreiben.

Bhagat007
quelle