Zwei Datenbankarchitekturen: Operativ und historisch

8

Ich dachte über eine ungewöhnliche Datenbankstruktur nach und fragte mich, ob jemand sie schon einmal gesehen hatte. Grundsätzlich werden 2 Datenbanken verwendet:

  • Die erste Datenbank enthält nur die aktuell gültigen Daten
  • Die zweite Datenbank enthält den Verlauf aller Daten, die jemals in der ersten Datenbank eingegeben, aktualisiert oder gelöscht wurden

Szenario

Ich arbeite an einem Projekt, in dem ich alles protokollieren muss, was passiert, und in dem sich die Daten häufig ändern.

Beispiel (nicht das echte)

Sie müssen das Datenbankdesign für eine Fußballliga durchführen. In dieser Liga gibt es Spieler und Mannschaften. Die Spieler wechseln oft die Mannschaft.

  • Erste Anforderung : Die Datenbank muss die Informationen enthalten, die für das nächste Spiel erforderlich sind. Dies bedeutet eine Liste aller Spieler, Teams und in welchem ​​Team sich jeder Spieler gerade befindet.
  • Zweite Anforderung : Die Datenbank muss historische Werte enthalten, anhand derer Statistiken erstellt werden. Dies bedeutet die Liste aller Spieler, die Teil eines Teams waren, oder die Liste aller Teams, zu denen ein Spieler gehört hat.

Das Problem

Diese beiden Anforderungen sind ein bisschen das Gegenteil voneinander. Ich habe versucht, alles in derselben Datenbank zu tun, aber es macht keinen Sinn. Die erste Anforderung befasst sich nur mit dem "Spielen des nächsten Spiels", während sich die zweite Anforderung nur mit dem "Generieren von Statistiken" befasst.

Um alles in derselben Datenbank zu erledigen, habe ich eine Art "Nur einfügen" -Datenbank verwendet, bei der das offensichtliche weiche Löschen zum Löschen / Aktualisieren von Informationen verwendet wurde ...

Was anfangs wie eine leichte Aufgabe schien, eine Liste von Spielern, Teams und dem aktuellen Team jedes Spielers zu führen, wird plötzlich viel schwieriger. Die Anwendungslogik, die zum Spielen des nächsten Spiels erforderlich ist, ist bereits kompliziert genug, aber jetzt hat die Datenbank ein sehr wenig hilfreiches Design, bei dem die Anwendung bei jeder einzelnen Abfrage die Überprüfung "gelöscht" hinzufügen muss , um das nächste Spiel zu spielen.

Möchten Sie der Trainer sein, der "alle Spieler im Team, komm zu mir" schreit und dann 2000 Spieler auf dich zukommen. An diesem Punkt werden Sie wahrscheinlich "alle Spieler , die nicht im Team gelöscht wurden , kommen zu mir" rufen (während Sie über dieses dumme Design schwören).

Meine Schlussfolgerung

Ich habe mich gefragt, warum Sie alles in dieselbe Datenbank stellen müssen. Das weiche Löschen kann nicht nur alles schlecht protokollieren, es sei denn, Sie fügen viele Spalten hinzu (time_created, who_created_it, time_deleted, who_deleted_it), sondern erschwert auch alles. Dies verkompliziert das Datenbankdesign und das Anwendungsdesign.

Außerdem erhalte ich diese beiden Anforderungen als Teil einer einzelnen Anwendung, die nicht aufgeteilt werden kann, aber ich denke immer wieder: Dies sind zwei völlig unterschiedliche Anwendungen. Warum versuche ich alles zusammen zu machen?

Da habe ich darüber nachgedacht, die Datenbank in zwei Teile zu teilen. Eine Betriebsdatenbank, die nur zum Spielen des nächsten Spiels verwendet wird und nur die aktuell gültigen Informationen enthält, und eine historische Datenbank, die alle Informationen enthält, die jemals vorhanden waren, als sie erstellt, gelöscht wurden und wer sie ausgeführt hat.

Ziel ist es, die erste Datenbank (betriebsbereit) und die Anwendung so einfach wie möglich zu halten und gleichzeitig so viele Informationen wie möglich in der zweiten Datenbank (historisch) zu haben.

Fragen

  • Haben Sie dieses Design schon einmal gesehen? Hat es einen Namen?
  • Gibt es offensichtliche Fallstricke, die mir fehlen?



EDIT 2015-03-16

Aktuelle Architektur

Grundsätzlich können Sie sich die gesamte Architektur in zwei Schritten vorstellen.

Schritt 1 :

  • Die Anwendung wird ausgeführt und Benutzer führen einige Aktionen aus
  • Jedes Mal, wenn ein Ereignis eintritt, wird es automatisch (Audit-Lösung) in einer Ereignistabelle aufgezeichnet
  • Dann wird die richtige Zeile in der Betriebsdatenbank aktualisiert

Schritt 2 :

  • Ein Job liest die letzte Einfügung in die Ereignistabelle und fügt diese neuen Daten in die historische Datenbank ein.
  • Benutzer fragen die historische Datenbank ab, um die benötigten Informationen abzurufen.

Nur aus der Ereignistabelle können Sie die Informationen zu jedem Zeitpunkt rekonstruieren. Das Problem ist, dass diese Ereignistabelle nicht einfach abfragbar ist. Hier setzt die historische Datenbank an. um die Daten so darzustellen, dass es einfach ist, genau das abzurufen, was wir wollen.

Zusätzliche Probleme, wenn alles in die gleichen Tabellen gestellt wird

Ich habe bereits meine Besorgnis über die zusätzliche Komplexität der Überprüfung "wird gelöscht" bei jeder Abfrage zum Ausdruck gebracht. Aber es gibt noch ein anderes Problem: Integrität .

Ich verwende häufig Fremdschlüssel und Einschränkungen , um sicherzustellen, dass die Daten in meiner Datenbank zu jedem Zeitpunkt gültig sind.

Schauen wir uns ein Beispiel an:

Einschränkung: Es kann nur einen Torhüter pro Team geben.

Es ist einfach, einen eindeutigen Index hinzuzufügen, der überprüft, ob es nur einen Torhüter pro Team gibt. Aber was passiert dann, wenn Sie den Torhüter wechseln? Sie müssen die Informationen über die vorherige noch beibehalten, aber jetzt haben Sie zwei Torhüter in denselben Teams, eine aktive und eine inaktive, was Ihrer Einschränkung widerspricht.

Sicher, es ist einfach, Ihrer Einschränkung einen Scheck hinzuzufügen, aber es ist eine andere Sache, die Sie verwalten und überlegen müssen.

Gudradain
quelle
Werfen
1
Überprüfenswert: Event Sourcing . Eine Ihrer Tabellen ist das Ereignisprotokoll, das einen vollständigen Prüfpfad bereitstellt. Ein Teil davon kann später archiviert werden. Eine andere Tabelle ist der aktuelle Zusammenfassungsstatus, der durch Anwenden von Änderungen aus jedem Ereignis erstellt wird. Es kann frühere Prüfpunkte enthalten, um die Wiederherstellung nur von einem Teil des Ereignisstroms zu ermöglichen.
9000

Antworten:

7

Es kommt ziemlich oft vor, obwohl der Verlauf (manchmal als Audit-Aufzeichnungen bezeichnet) entweder in derselben Tabelle oder in einer separaten Tabelle in derselben Datenbank gespeichert ist.

Ich habe beispielsweise mit einem System gearbeitet, bei dem Aktualisierungen einer Tabelle als Einfügung implementiert wurden, auf dem alten "aktuellen" Datensatz ein Flag gesetzt war, das besagt, dass es sich um einen historischen Datensatz handelt, und der Zeitstempel, als er aktualisiert wurde in eine Spalte geschrieben.

Heute arbeite ich an einem System, bei dem jede Änderung in eine dedizierte Prüftabelle geschrieben wird und die Aktualisierung dann in der Tabelle erfolgt.

Letzteres ist skalierbarer, aber nicht so einfach generisch zu implementieren.

Der einfachste Weg, um Ihr Ziel zu erreichen, Abfragen einfach zu gestalten und nicht das Flag "Ist aktuell" hinzuzufügen, besteht darin, Leseanfragen nur über eine Ansicht oder eine gespeicherte Prozedur zuzulassen. Dann rufen Sie an und sagen "Alle Spieler holen". Der gespeicherte Prozess gibt nur aktuelle Spieler zurück (Sie können ein zweites Verfahren implementieren, um Spieler mit mehr Kontrolle darüber zurückzugeben, welche zurückgegeben werden). Dies funktioniert auch gut zum Schreiben. Eine gespeicherte Prozedur zum Aktualisieren eines Players kann dann alle erforderlichen Verlaufsdetails schreiben und den Player aktualisieren - ohne dass der Client jemals den Verlaufsmechanismus kennt. Aus diesem Grund sind gespeicherte Prozeduren besser als eine Ansicht, die nur aktuelle Player zurückgibt, da der gesamte DB-Zugriffsmechanismus beim Lesen und Schreiben gleich bleibt - alles läuft über einen Sproc ab.

gbjbaanb
quelle
Derzeit bevorzuge ich das spätere. Es scheint keine große Sache zu sein, alle Ihre Abfragen über gespeicherte Prozeduren oder Ansichten auszuführen, aber es erhöht die Komplexität, alle zu verwalten. Das Anzeigen und Speichern von Prozeduren führt auch zu vielen Einschränkungen. blog.sqlauthority.com/2010/10/03/… stackoverflow.com/questions/921190/…
Gudradain
1
Einschränkungen sind gut, es ist wie zu sagen, "lokale Variablen in Objekten hindern mich daran, Globale zu verwenden". Wenn Sie Ihre Datenzugriffsfläche einschränken, ist sie sicherer und Sie müssen besser gestalten. Das sind gute Dinge. Die Links: Ansichten sind einschränkend, sie sind nicht als Ersatztabellen konzipiert. Ein Sproc, an dem Sie nicht teilnehmen können, bedeutet, dass Sie einen anderen Sproc benötigen. Das Schreiben von SQL in Sprocs ist nicht schlechter als das Schreiben in clientseitigem Code. Sie pflegen dies perfekt, sodass Sie Ihren Sproc-Code genauso einfach verwalten können.
Gbjbaanb
1
@ Gudradain Ich bin mit Gbjbaanb. Ein Hass auf gute Client-Server-Praktiken basiert auf einem schlecht geschriebenen Blog-Beitrag, der sich auf ein RDBMS bezieht, und einem irrelevanten Link zu einer Frage zum Stapelüberlauf, bei der jemand versucht, mit einer gespeicherten Prozedur etwas Unnatürliches zu tun, und dies nicht kann. Grundsätzlich lesen Sie Ansichten durch und schreiben durch gespeicherte Prozesse. Ja, Sie müssen sich um die Versionskontrolle und -freigabe kümmern - aber das brauchen Sie trotzdem.
Mcottle
@mcottle Das Durchlaufen von Ansicht und Sproc erscheint nur dann unpraktisch, wenn in einem Projekt bereits ein ORM und eine Datenzugriffsschicht verwendet werden. Wenn Sie alles in die Datenbank stellen, kann die Programmlogik schlecht gekapselt werden. Oft haben Sie mehr als eine Anwendung, die dieselbe Datenbank verwendet. Es ist einfach nicht sinnvoll, alle gespeicherten Prozeduren, die sich auf viele verschiedene Anwendungen beziehen, am selben Ort zu haben. Wenn ich diesen Ansatz wählen müsste, überall "wird gelöscht" hinzuzufügen, würde ich dies in meiner Datenzugriffsschicht (in meiner Anwendung) tun.
Gudradain
@Gudradain Ja, es funktioniert, da "viele verschiedene Anwendungen" gerne dieselben Tabellen und Daten verwenden. Stellen Sie sich einen Sproc als eine andere Form der Tabelle vor als eine in die DB-Schicht eingefügte Client-Logik. Sie können sie weiterhin über Ihr ORM aufrufen. Wenn Sie wirklich möchten, dass viele verschiedene Anwendungen sie verwenden, verwenden Sie Schemas, um sie zu isolieren. Dadurch wird Ihre DB anwendungsspezifisch, was für Sicherheit und Wartung sehr gut ist (da 1 App dann ihre ändern kann Daten-API, ohne andere Anwendungen zu beeinflussen). Sprocs sind bewährte Methoden. Der Client-Code vergisst möglicherweise, "wird gelöscht" hinzuzufügen. Sproc stellt dies sicher.
Gbjbaanb
4

Wenn Sie eine Datenbank in zwei Datenbanken aufteilen, verlieren Sie alle Vorteile relationaler Referenzen und der Überprüfung der referenziellen Integrität. Ich habe so etwas noch nie versucht, aber ich vermute, dass es ein großer Albtraum werden würde.

Ich glaube, dass der gesamte Datensatz, der ein bestimmtes System beschreibt, zu einer einzigen Datenbank gehört. Fragen der Benutzerfreundlichkeit beim Zugriff auf die Daten sind fast nie ein guter Grund, um Entscheidungen zur Datenorganisation zu treffen.

Probleme mit dem Komfort beim Zugriff auf Ihre Daten sollten gelöst werden, indem Sie alle Komfortfunktionen nutzen, die Ihr RDBMS bietet.

Anstatt eine 'aktuelle' Datenbank und eine 'historische' Datenbank zu haben, sollten Sie nur eine Datenbank haben und allen darin enthaltenen Tabellen sollte 'historisch' vorangestellt werden. Anschließend sollten Sie eine Reihe von Ansichten erstellen, eine für jede Tabelle, die Sie als "aktuell" anzeigen möchten, und jede Ansicht die historischen Zeilen herausfiltern lassen, die Sie nicht sehen möchten, und nur die aktuellen durchlassen.

Dies ist eine geeignete Lösung für Ihr Problem, da eine Komfortfunktion des RDBMS verwendet wird, um ein Komfortproblem des Programmierers zu lösen und das Datenbankdesign intakt zu lassen.

Ein Beispiel für ein Problem, auf das Sie wahrscheinlich stoßen (zu lang für einen Kommentar)

Angenommen, Sie sehen einen Bildschirm, auf dem aktuelle Informationen zu einem Team angezeigt werden, z. B. team.id = 10, team.name = "Manchester United", und klicken auf die Schaltfläche "Verlauf anzeigen". Zu diesem Zeitpunkt möchten Sie zu einem Bildschirm wechseln, auf dem historische Informationen zu demselben Team angezeigt werden. Sie nehmen also die ID 10, von der Sie wissen, dass sie in der "aktuellen" Datenbank für "Manchester United" steht, und Sie müssen hoffendass diese ID-Nummer 10 auch für "Manchester United" in der historischen Datenbank steht. Es gibt keine referenzielle Integritätsregel, die erzwingt, dass sich die ID in beiden Datenbanken auf genau dieselbe Entität bezieht. Daher verfügen Sie im Wesentlichen über zwei vollständig getrennte Datensätze mit impliziten Verbindungen, die nur bekannt sind, von diesen anerkannt werden und deren Aufrechterhaltung versprochen wird durch Code außerhalb der Datenbank.

Und dies gilt natürlich nicht nur für große Tische wie den "Teams" -Tisch, sondern auch für den kleinsten kleinen Tisch, den Sie auf der Seite haben werden, wie "Spielerpositionen: Stürmer, Mittelfeldspieler, Torhüter usw.".

Historizität in derselben Datenbank erreichen

Es gibt verschiedene Methoden, um die Historizität aufrechtzuerhalten, und obwohl sie den Rahmen dieser Frage sprengen, die im Grunde genommen die Fallstricke dieser besonderen Idee von Ihnen haben könnte, ist hier eine Idee:

Sie können eine Protokolltabelle verwalten, die einen Eintrag für jede einzelne Änderung enthält, die jemals an der Datenbank vorgenommen wurde. Auf diese Weise können alle "aktuellen" Tabellen vollständig von Daten gelöscht und durch Wiedergabe der protokollierten Änderungen vollständig rekonstruiert werden. Wenn Sie die "aktuellen" Tabellen durch Wiedergabe der Änderungen vom Beginn der Zeit bis jetzt rekonstruieren können, können Sie natürlich auch einen temporären Satz von Tabellen erstellen, um durch Wiedergabe eine Ansicht der Datenbank zu einer bestimmten Zeitkoordinate zu erhalten die Änderungen vom Beginn der Zeit bis zu dieser bestimmten Zeitkoordinate.

Dies ist als "Event Sourcing" bekannt (Artikel von Martin Fowler).

Mike Nakis
quelle
Meinen Sie relationale Referenzen und referenzielle Integrität zwischen den beiden Datenbanken oder innerhalb einer Datenbank? Ich verwende Fremdschlüssel und Einschränkungen überall dort, wo sie verwendet werden, da nur Daten in die Datenbank eingefügt werden sollten, die diese Einschränkungen berücksichtigen.
Gudradain
Soweit ich weiß, können Sie nur Beziehungen innerhalb einer einzigen Datenbank haben. Möglicherweise gibt es RDBMS, die datenbankübergreifende Beziehungen ermöglichen, aber das ist von anderen Produkten nicht zu erwarten und meiner bescheidenen Meinung nach auch bei dem Produkt, das für eine solche Funktion wirbt, nicht zu verlassen.
Mike Nakis
Wenn Sie die Datenbank in zwei Datenbanken aufteilen, können Sie Beziehungen innerhalb jeder Datenbank separat herstellen, jedoch nicht zwischen den beiden Datenbanken. Was eine Katastrophe bedeuten kann.
Mike Nakis
1
Die Daten in der historischen Datenbank stammen ausschließlich aus der Betriebsdatenbank, und in dieser Datenbank werden niemals Aktualisierungen / Löschungen vorgenommen. Aus meiner Sicht benötigt diese Datenbank nicht einmal Beziehungen oder Einschränkungen. Es enthält einfach die Daten, die sich irgendwann in der Betriebsdatenbank befanden. Es gibt keine Manipulation oder irgendetwas, um diese Daten zu überprüfen. Das einzige, was zählt, ist: Existierte es in der anderen Datenbank (ja / nein)? Ich verstehe irgendwie nicht, was das Problem damit ist ...
Gudradain
Da dies für einen Kommentar zu lang wäre, habe ich ihn als Ergänzung zu meiner Antwort hinzugefügt.
Mike Nakis
2

Das Wichtigste zuerst : Bietet Ihre Codebasis bereits eine saubere Trennung von Bedenken, bei denen die Geschäftslogik (Auswahl der Spieler für das nächste Spiel) von Ihrer Datenbankzugriffslogik (eine Ebene, die einfach eine Verbindung zur Datenbank herstellt und Ihre Datenstrukturen abbildet) unterschieden wird in Datenbankzeilen und umgekehrt)? Die Antwort darauf wird viel dazu beitragen, zu erklären, warum Sie damit zu tun haben:

Dies verkompliziert das Datenbankdesign und das Anwendungsdesign.

Jetzt...

Die Anwendungslogik, die zum Spielen des nächsten Spiels erforderlich ist, ist bereits kompliziert genug, aber jetzt hat die Datenbank ein sehr wenig hilfreiches Design, bei dem die Anwendung bei jeder einzelnen Abfrage die Überprüfung "gelöscht" hinzufügen muss, um das nächste Spiel zu spielen.

Angenommen, Sie sprechen von RDBMS, können Sie immer noch über eine bitemporale Datenbank verfügen , die alle gültigen Daten der Vergangenheit, Gegenwart und möglicherweise der Zukunft erfasst, und dann ein ausreichend robustes Datenbankzugriffsbibliothek- / ORM-Framework verwenden, um die Datenbankabfragelogik für Sie zu verwalten. Sie können sogar eine Datenbankansicht verwenden, um Ihre Auswahl zu erleichtern. Dann sollten die Geschäftslogik-Teile Ihres Codes die zugrunde liegenden zeitlichen Felder nicht kennen müssen, wodurch das oben beschriebene Problem behoben wird.

Anstatt beispielsweise eine SQL-Abfrage in Ihrer Anwendung fest zu codieren:

SELECT * FROM team_players WHERE team_id = ? AND valid_from >= ? AND valid_to <= ? AND ...

(Verwendung ?als Parameterbindungen)

Mit einer hypothetischen Datenbankzugriffsbibliothek können Sie möglicherweise Folgendes abfragen: (Pseudocode):

dbConnection.select(Table.TEAM_PLAYERS).match(Field.TEAM_ID, <value>).during(Season.NOW)

Oder verwenden Sie den Ansatz der Datenbankansicht:

-- Using MySQL dialect for illustration
CREATE VIEW seasonal_players AS SELECT * FROM team_players 
    WHERE valid_from >= ... AND valid_to <= ... AND ...

Sie können dann während dieses Zeitraums nach Spielern fragen:

SELECT * FROM seasonal_players WHERE team_id = ?

Wie wollen Sie, zurück zu Ihrem vorgeschlagenen Datenbankmodell , mit dem Entfernen historischer Daten aus Ihrer Betriebsdatenbank umgehen? INSERTFühren Sie einfach zwei ähnliche Zeilen in Ihre Betriebs- und Verlaufsdatenbanken ein und führen Sie dann eine DELETEin der Betriebsdatenbank aus, wenn eine Benutzeraktion zum Löschen von Verlaufsdaten erfolgt?


Groß denken

Wenn Sie von einer umfangreichen Datenverarbeitung sprechen, bei der Ihre 'Datenbank' eine skalierte verteilte Datenbank-Clustering- / Stream-Verarbeitungslösung ist, klingt Ihr Ansatz dem Lambda vage ähnlich (wahrscheinlich nur unter einigen der definierten Begriffe) Architektur , bei der Ihre "historischen" Daten (dh vergangene Echtzeitdaten) separat stapelweise verarbeitet werden, um die Art von Statistiken auszuführen, nach denen Sie suchen, und Ihre "betrieblichen" Daten (dh Streaming-Echtzeitdaten) weiterhin abfragbar sind Ein vordefinierter Grenzwert, bevor die Stapelverarbeitung diese beibehält. Die Grundlage dieses Ansatzes liegt jedoch mehr in den Vor- und Nachteilen aktueller Big Data-Implementierungen als in der bloßen Vereinfachung der eigenen Anwendungslogik.


bearbeiten (nach dem Bearbeiten des OP)

Ich hätte früher darauf antworten sollen, aber trotzdem:

Außerdem erhalte ich diese beiden Anforderungen als Teil einer einzelnen Anwendung, die nicht aufgeteilt werden kann, aber ich denke immer wieder: Dies sind zwei völlig unterschiedliche Anwendungen. Warum versuche ich alles zusammen zu machen?

Dies liegt im Allgemeinen daran, dass Endbenutzer in der Regel in Bezug auf Funktionen und nicht in Bezug auf die Anzahl der erforderlichen Datenbanken denken .

Sie erwähnen auch, dass:

Schritt 1:

  • Jedes Mal, wenn ein Ereignis eintritt, wird es automatisch (Audit-Lösung) in einer Ereignistabelle aufgezeichnet.
  • Dann wird die richtige Zeile in der Betriebsdatenbank aktualisiert.

Schritt 2:

  • Ein Job liest die letzte Einfügung in die Ereignistabelle und fügt diese neuen Daten in die historische Datenbank ein.

Großartig! Jetzt haben Sie also eine Ereignistabelle, von der ich annehme, dass sie das in den anderen Antworten erwähnte Event-Sourcing- Konzept ist. Was liest jedoch Ihre Ereignistabelle und aktualisiert die richtige Zeile in der Betriebsdatenbank ? Entspricht das dem Job, der das letzte Ereignis liest und in die historische Datenbank einfügt ?

Noch ein Punkt zu Ihrem Einschränkungsbeispiel:

Ich verwende häufig Fremdschlüssel und Einschränkungen, um sicherzustellen, dass die Daten in meiner Datenbank zu jedem Zeitpunkt gültig sind.

Schauen wir uns ein Beispiel an:

Einschränkung: Es kann nur einen Torhüter pro Team geben. ( aktiv auf dem Spielfeld während eines Spiels, nur eine Randnotiz )

Bezieht sich " irgendein Zeitpunkt " auf eine gültige Zeit oder Transaktionszeit ?

Was passiert, wenn wir einen dritten neuen Torhüter haben? Erstellen Sie eine eindeutige Einschränkung für zeitliche Felder in der historischen Datenbank, um die Daten für zwei "alte" Torhüter gültig zu halten?

hjk
quelle
Bevor ich etwas einfüge / aktualisiere / lösche, erstelle ich ein Ereignis, das alle Informationen enthält, die zur Rekonstruktion der Daten zu diesem Zeitpunkt erforderlich sind, und aktualisiere dann einfach die Betriebsdatenbank. Danach füge ich die Ereignisinformationen zur historischen Datenbank hinzu. Der Prozess ist größtenteils automatisch und Sie haben kaum etwas zu warten.
Gudradain
1
Die Ereignisse werden durch Trigger direkt in den Tabellen erstellt. Entweder wird das Ereignis gespeichert und die Zeile wird erstellt / aktualisiert / gelöscht oder es passiert nichts. So passiert es zur gleichen Zeit. Auf diese Weise wird sichergestellt, dass das Ereignis erstellt wird, und es wird sichergestellt, dass das Ereignis versucht, etwas zu tun, das gemäß der Beziehung und Einschränkung in der Betriebsdatenbank gültig ist.
Gudradain
1

Dies ähnelt der Art und Weise, wie Datenbanktransaktionen im Allgemeinen implementiert werden, mit der Ausnahme, dass die historischen Daten normalerweise weggeworfen werden, nachdem sie in die Betriebsdatenbank geschrieben wurden. Das nächste Programmiermuster, an das ich denken kann, ist Event Sourcing .

Ich denke, die Aufteilung dieser beiden Datenbanken ist der richtige Schritt. Insbesondere würde ich die "betriebliche" Datenbank als Cache betrachten, da die historischen Daten ausreichen, um die betriebliche Datenbank jederzeit neu zu erstellen. Abhängig von der Art Ihrer Anwendung und den Leistungsanforderungen kann es nicht erforderlich sein, diesen Cache als separate Datenbank zu verwalten, wenn es sinnvoll ist, den aktuellen Status bei jedem Programmstart aus den historischen Daten im Speicher zu rekonstruieren.

In Bezug auf Fallstricke besteht das Hauptproblem darin, dass Sie irgendeine Art von Parallelität benötigen (entweder im selben Programm oder indem mehrere Clients gleichzeitig die Datenbank verwenden). In diesem Fall möchten Sie sicherstellen, dass die Änderungen an den historischen und betrieblichen Datenbanken atomar vorgenommen werden. Im Falle einer Parallelität innerhalb desselben Programms ist Ihre beste Wahl wahrscheinlich eine Art Sperrmechanismus. Für mehrere Clients, die mit derselben Datenbank interagieren, besteht der einfachste Weg darin, beide als Tabellen in derselben Datenbank zu speichern und Transaktionen zu verwenden, um die Datenbank konsistent zu halten.

John Colanduoni
quelle
1
Event Sourcing ist eigentlich ziemlich nah an dem, was ich derzeit habe. Aus jedem Einfügen / Aktualisieren / Löschen wird automatisch ein Prüfpfad generiert, der mit der Liste der Ereignisse verglichen werden kann.
Gudradain