Wie wird die Aufzeichnung jeder Änderung einer Zeile in einer Datenbank im Allgemeinen gespeichert?

10

In einem Projekt, an dem ich arbeite, muss jede Änderung an den Zeilen in einigen Tabellen der Datenbank für eine weitere Prüfung oder ein Rollback nachverfolgt werden . Es muss leicht zu finden sein, wer die Zeile von welcher IP-Adresse und wann geändert hat, und die vorherige Version wiederherstellen können.

Ähnliches wird beispielsweise von Stack Exchange verwendet. Wenn ich die Frage eines anderen ändere, kann ich feststellen, dass ich sie geändert habe, und die Änderungen rückgängig machen.

Mit welcher allgemeinen Technik wird jede Änderung an einem Objekt in einer Datenbank gespeichert , da mein aktuelles Schema im Wesentlichen dieselben Eigenschaften (unten) aufweist wie eine durchschnittliche Geschäftsanwendung?

  • Die Objekte sind relativ klein: Es gibt möglicherweise einige nvarchar(1000), aber keine großen Blobs von Binärdaten, die direkt auf der Festplatte gespeichert werden und auf die direkt zugegriffen wird, und nicht über Microsoft SQL filestream.
  • Die Datenbanklast ist ziemlich gering und die gesamte Datenbank wird von einer virtuellen Maschine auf einem Server verwaltet.
  • Der Zugriff auf die vorherigen Versionen muss nicht so schnell sein wie der Zugriff auf die neueste Version, muss jedoch aktuell sein¹ und nicht zu langsam².

<tl-dr>

Ich habe über die folgenden Fälle nachgedacht, aber ich habe keine wirklichen Erfahrungen mit solchen Szenarien, daher würde ich die Meinungen anderer hören:

  1. Speichern Sie alles in derselben Tabelle und unterscheiden Sie die Zeilen nach ID und Version. IMO, es ist ernsthaft dumm und wird bald oder später auf Leistungsniveau schaden. Mit diesem Ansatz ist es auch unmöglich, eine andere Sicherheitsstufe für die neuesten Elemente und die Versionsverfolgung festzulegen. Schließlich wäre jede Abfrage komplizierter zu schreiben. Um auf die aktuellen Daten zugreifen zu können, wäre ich gezwungen, alles nach ID zu gruppieren und in jeder Gruppe die letzte Version abzurufen.

  2. Speichern Sie die neueste Version in einer Tabelle und kopieren Sie bei jeder Änderung die veraltete Version in eine andere Tabelle in einem anderen Schema. Der Fehler ist, dass wir jedes Mal jeden Wert speichern, auch wenn er sich nicht geändert hat. Das Setzen von unveränderten Werten auf nullist keine Lösung, da ich auch verfolgen muss, wann der Wert zu nulloder von geändert wird null.

  3. Speichern Sie die neueste Version in einer Tabelle und die Liste der geänderten Eigenschaften mit ihren vorherigen Werten in einer anderen Tabelle. Dies scheint zwei Fehler zu haben: Der wichtigste ist, dass die einzige Möglichkeit, heterogene Typen vorheriger Werte in derselben Spalte zu sortieren, darin besteht, a zu haben binary(max). Das zweite ist, dass es meiner Meinung nach schwieriger wäre, eine solche Struktur zu verwenden, wenn dem Benutzer die vorherigen Versionen angezeigt werden.

  4. Gehen Sie genauso vor wie in zwei vorherigen Punkten, speichern Sie die Versionen jedoch in einer separaten Datenbank. In Bezug auf die Leistung kann es interessant sein, den Zugriff auf die neuesten Versionen nicht zu verlangsamen, indem die vorherigen Versionen in derselben Datenbank gespeichert werden. Dennoch glaube ich, dass dies eine vorzeitige Optimierung ist und nur durchgeführt werden muss, wenn es einen Beweis dafür gibt, dass ältere und neueste Versionen in derselben Datenbank ein Engpass sind.

</ tl-dr>


¹ Es ist beispielsweise nicht akzeptabel, die Änderungen in einer Protokolldatei zu speichern, wie dies bei HTTP-Protokollen der Fall ist, und die Daten nachts aus dem Protokoll in die Datenbank zu löschen, wenn die Serverlast am niedrigsten ist. Die Informationen zu verschiedenen Versionen müssen sofort oder fast sofort verfügbar sein. Eine Verzögerung von einigen Sekunden ist akzeptabel.

² Auf die Informationen wird nicht sehr häufig und nur von einer bestimmten Benutzergruppe zugegriffen. Es wäre jedoch nicht akzeptabel, sie zu zwingen, 30 Sekunden auf die Anzeige der Versionsliste zu warten. Auch hier ist eine Verzögerung von einigen Sekunden akzeptabel.

Arseni Mourzenko
quelle
3
Relevant: SQL Server Change Data Capture .
Nick Chammas

Antworten:

8

Die normale Art der Überwachungsprotokollierung dieser Art besteht darin, eine Schattentabelle zu haben und Änderungen mit Triggern in der Basistabelle zu protokollieren, die Sie überwachen. Die anderen Tabellen können auf einer anderen physischen Festplatte abgelegt werden, wenn dies für die Leistung erforderlich ist, und Sie können Indizes auf sie setzen, wenn Sie das schnelle Abrufen der Daten unterstützen möchten.

Die Tabellen haben ungefähr die gleiche Struktur wie Ihre ursprünglichen Tabellen, jedoch eine Datums- / Uhrzeitspalte für den Zeitpunkt der Änderung und eine Markierung dafür, ob die Zeile eingefügt, geändert oder gelöscht wurde. Die Sequenzierung der Versionen kann über den Zeitstempel erfolgen.

Das Änderungsdatum kann vorgenommen werden, indem die datetime-Spalte mit dem Standardwert getdate () nicht null gemacht wird. Eine Überwachungsbenutzerspalte erfasst den Benutzer mit einer Nicht-Null-Spalte, die standardmäßig Suser_Sname () ist. Angenommen, der tatsächliche Benutzer wird in der Sitzung imitiert, wird die Identität des Benutzers erfasst, der die Änderung vornimmt.

Die Datenbank kann die IP-Adresse, die eine Verbindung zu einem Webserver herstellt, nicht kennen. Die Anwendung muss die IP-Adresse bei der Transaktion explizit erfassen und protokollieren.

Wenn Sie eine große Anzahl von Tabellen haben, die Sie prüfen möchten, können Sie die Trigger mithilfe der Metadaten aus dem Systemdatenwörterbuch programmgesteuert generieren.

Diese Lösung ist aus mehreren Gründen bei weitem die beste:

  • Es erfasst alle Änderungen an der Tabelle, nicht nur die von der Anwendung vorgenommenen.

  • Die Überwachungstabellen können auf einem anderen Satz von Datenträgern abgelegt werden, um die E / A-Belastung Ihrer primären Tabellen zu verringern.

  • Sie können eine Ansicht verwenden, die auf einer Vereinigung der Tabelle und der Überwachungsprotokolltabelle basiert und den gesamten Verlauf einschließlich der aktuellen Version anzeigt.

  • Sie können die Überwachungsprotokolltabellen nach Bedarf indizieren, damit die Überwachungsbenutzer sie reaktionsschnell abfragen können. Wie üblich ist die Indexauswahl ein Kompromiss zwischen Abfrageleistung und Aktualisierungsaufwand.

ConcernedOfTunbridgeWells
quelle
Sie versuchen zu sagen, wenn ich 1000 Tabelle habe, die ich Protokoll für jede Änderung pflegen muss, dann muss ich 1000 Schattentabelle erstellen, nicht wahr? und 1000 Trigger zum Erfassen der Änderung? Wenn ja, dann ist es eine falsche Idee ... Wir können eine einzelne Verlaufstabelle und einen einzelnen Trigger erstellen, um die geänderten Daten zu erfassen und zu protokollieren. Wir können alte und neue Zeilendaten in dieser Tabelle als XML speichern. Das ist, was viele Leute tun. Bin ich klar?
Thomas
1
Für 1000 Tabellen schreiben Sie eine Utlity, die die Definitionen aus dem Systemdatenwörterbuch liest und die Trigger und Tabellendefinitionen generiert. Ich habe es auf einem System mit 560 Tabellen gemacht und es funktioniert einwandfrei.
ConcernedOfTunbridgeWells
0

Ich kenne viele CMS-Systeme (einschließlich Wordpress), die eine einzige Tabelle zum Speichern aller Versionen der Daten verwenden. Andererseits müssen sie dies nur für die Tabelle tun, die die Blog-Beiträge enthält. Siehe die Wordpress-Datenbankstruktur .

Auch die Anzahl der Datensätze und die Anzahl der Revisionen, die jede Zeile durchläuft, spielen eine wichtige Rolle bei Ihrer Entscheidung.

Dharmendar Kumar 'DK'
quelle
0

Informationen zur CMS-Versionierung; Für Drupal wird eine spezielle Tabelle für jedes Feld der Entität erstellt, in der der alte Wert gespeichert ist. Ein solches Konzept ermöglicht Ihnen eine Feinmanipulation Ihrer Daten, aber ich denke, es ist teuer. Meine eigene Lösung besteht darin, mein Objekt in das XML-Format zu konvertieren und es als Zeichenfolge mit den anderen Feldern (Änderungszeit, ID ...) zu speichern.

Bourkadi
quelle