Eine häufig verwendete Anforderung in Datenbankanwendungen besteht darin, Änderungen an einer oder mehreren bestimmten Entitäten in einer Datenbank zu verfolgen. Ich habe gehört, dass dies als Zeilenversionierung, Protokolltabelle oder Verlaufstabelle bezeichnet wird (ich bin sicher, dass es andere Namen dafür gibt). Es gibt verschiedene Möglichkeiten, dies in einem RDBMS zu tun: Sie können alle Änderungen aus allen Quelltabellen in eine einzelne Tabelle (eher ein Protokoll) schreiben oder für jede Quelltabelle eine separate Verlaufstabelle haben. Sie haben auch die Möglichkeit, entweder die Anmeldung im Anwendungscode oder über Datenbank-Trigger zu verwalten.
Ich versuche zu überlegen, wie eine Lösung für dasselbe Problem in einer NoSQL / Dokument-Datenbank (insbesondere MongoDB) aussehen würde und wie sie auf einheitliche Weise gelöst werden würde. Wäre es so einfach, Versionsnummern für Dokumente zu erstellen und diese niemals zu überschreiben? Separate Sammlungen für "echte" oder "protokollierte" Dokumente erstellen? Wie würde sich dies auf die Abfrage und die Leistung auswirken?
Wie auch immer, ist dies ein häufiges Szenario mit NoSQL-Datenbanken, und wenn ja, gibt es eine gemeinsame Lösung?
Antworten:
Gute Frage, ich habe mich auch selbst darum gekümmert.
Erstellen Sie bei jeder Änderung eine neue Version
Ich bin auf das Versionierungsmodul des Mongoid-Treibers für Ruby gestoßen. Ich habe es selbst nicht verwendet, aber nach allem, was ich finden konnte , fügt es jedem Dokument eine Versionsnummer hinzu. Ältere Versionen sind in das Dokument selbst eingebettet. Der Hauptnachteil besteht darin, dass bei jeder Änderung das gesamte Dokument dupliziert wird , was dazu führt, dass beim Umgang mit großen Dokumenten viel doppelter Inhalt gespeichert wird. Dieser Ansatz ist jedoch in Ordnung, wenn Sie mit kleinen Dokumenten arbeiten und / oder Dokumente nicht sehr oft aktualisieren.
Speichern Sie Änderungen nur in einer neuen Version
Ein anderer Ansatz wäre, nur die geänderten Felder in einer neuen Version zu speichern . Anschließend können Sie Ihren Verlauf reduzieren, um eine beliebige Version des Dokuments zu rekonstruieren. Dies ist jedoch recht komplex, da Sie Änderungen in Ihrem Modell verfolgen und Aktualisierungen und Löschvorgänge so speichern müssen, dass Ihre Anwendung das aktuelle Dokument rekonstruieren kann. Dies kann schwierig sein, da Sie sich eher mit strukturierten Dokumenten als mit flachen SQL-Tabellen befassen.
Speichern Sie Änderungen im Dokument
Jedes Feld kann auch einen eigenen Verlauf haben. Das Rekonstruieren von Dokumenten zu einer bestimmten Version ist auf diese Weise viel einfacher. In Ihrer Anwendung müssen Sie Änderungen nicht explizit verfolgen, sondern nur eine neue Version der Eigenschaft erstellen, wenn Sie ihren Wert ändern. Ein Dokument könnte ungefähr so aussehen:
Das Markieren eines Teils des Dokuments als in einer Version gelöscht ist jedoch immer noch etwas umständlich. Sie können ein
state
Feld für Teile einfügen, die aus Ihrer Anwendung gelöscht / wiederhergestellt werden können:Mit jedem dieser Ansätze können Sie eine aktuelle und reduzierte Version in einer Sammlung und die Verlaufsdaten in einer separaten Sammlung speichern. Dies sollte die Abfragezeiten verbessern, wenn Sie nur an der neuesten Version eines Dokuments interessiert sind. Wenn Sie jedoch sowohl die neueste Version als auch historische Daten benötigen, müssen Sie statt einer zwei Abfragen durchführen. Die Wahl zwischen einer einzelnen Sammlung und zwei getrennten Sammlungen sollte daher davon abhängen, wie oft Ihre Anwendung die historischen Versionen benötigt .
Der größte Teil dieser Antwort ist nur ein Brain Dump meiner Gedanken, ich habe noch nichts davon ausprobiert. Rückblickend ist die erste Option wahrscheinlich die einfachste und beste Lösung, es sei denn, der Overhead doppelter Daten ist für Ihre Anwendung sehr bedeutend. Die zweite Option ist ziemlich komplex und wahrscheinlich nicht die Mühe wert. Die dritte Option ist im Grunde eine Optimierung von Option zwei und sollte einfacher zu implementieren sein, ist aber wahrscheinlich den Implementierungsaufwand nicht wert, es sei denn, Sie können wirklich nicht mit Option eins gehen.
Ich freue mich auf Feedback zu diesem und den Lösungen anderer Leute für das Problem :)
quelle
Wir haben dies teilweise auf unserer Website implementiert und verwenden die 'Revisionen in einem separaten Dokument speichern' (und eine separate Datenbank). Wir haben eine benutzerdefinierte Funktion geschrieben, um die Unterschiede zurückzugeben, und wir speichern diese. Nicht so schwer und können eine automatisierte Wiederherstellung ermöglichen.
quelle
Warum nicht eine Variation von Store-Änderungen innerhalb des Dokuments ?
Anstatt Versionen für jedes Schlüsselpaar zu speichern, stellen die aktuellen Schlüsselpaare im Dokument immer den neuesten Status dar und ein 'Protokoll' von Änderungen wird in einem Verlaufsarray gespeichert. Nur die Schlüssel, die sich seit der Erstellung geändert haben, haben einen Eintrag im Protokoll.
quelle
Man kann eine aktuelle NoSQL-Datenbank und eine historische NoSQL-Datenbank haben. Es wird jeden Tag eine nächtliche ETL geben. Diese ETL zeichnet jeden Wert mit einem Zeitstempel auf, sodass es sich anstelle von Werten immer um Tupel (versionierte Felder) handelt. Es wird nur dann ein neuer Wert aufgezeichnet, wenn eine Änderung am aktuellen Wert vorgenommen wurde, wodurch Platz gespart wird. Diese historische json-Datei der NoSQL-Datenbank kann beispielsweise folgendermaßen aussehen:
quelle
Für Benutzer von Python (Python 3+ und höher ) gibt es HistoricalCollection , eine Erweiterung des Collection-Objekts von pymongo.
Beispiel aus den Dokumenten:
Vollständige Offenlegung, ich bin der Paketautor. :) :)
quelle