Ich schreibe das Schema für eine einfache Bankdatenbank. Hier sind die grundlegenden Spezifikationen:
- In der Datenbank werden Transaktionen für einen Benutzer und eine Währung gespeichert.
- Jeder Benutzer verfügt über einen Kontostand pro Währung. Jeder Kontostand ist also einfach die Summe aller Transaktionen mit einem bestimmten Benutzer und einer bestimmten Währung.
- Ein Saldo kann nicht negativ sein.
Die Bankanwendung kommuniziert mit ihrer Datenbank ausschließlich über gespeicherte Prozeduren.
Ich erwarte, dass diese Datenbank Hunderttausende neuer Transaktionen pro Tag akzeptiert und Abfragen in einer höheren Größenordnung ausgleicht. Um die Salden sehr schnell aufzufüllen, muss ich sie vorab aggregieren. Gleichzeitig muss ich garantieren, dass ein Kontostand niemals seiner Transaktionshistorie widerspricht.
Meine Optionen sind:
Haben Sie eine separate
balances
Tabelle und führen Sie einen der folgenden Schritte aus:Wenden Sie Transaktionen auf die Tabellen
transactions
und anbalances
. Verwenden SieTRANSACTION
Logik in meiner gespeicherten Prozedurebene, um sicherzustellen, dass Salden und Transaktionen immer synchron sind. (Unterstützt von Jack .)Wenden Sie Transaktionen auf die
transactions
Tabelle an und haben Sie einen Auslöser, der diebalances
Tabelle für mich mit dem Transaktionsbetrag aktualisiert .Wenden Sie Transaktionen auf die
balances
Tabelle an und haben Sie einen Auslöser, dertransactions
mir einen neuen Eintrag in der Tabelle mit dem Transaktionsbetrag hinzufügt .
Ich muss mich auf sicherheitsbasierte Ansätze verlassen, um sicherzustellen, dass keine Änderungen außerhalb der gespeicherten Prozeduren vorgenommen werden können. Andernfalls könnte beispielsweise ein Prozess eine Transaktion direkt in die
transactions
Tabelle einfügen, und1.3
der betreffende Saldo wäre nach dem Schema nicht synchron.Haben Sie eine
balances
indizierte Ansicht , die die Transaktionen entsprechend aggregiert. Die Speicher-Engine garantiert, dass die Salden mit ihren Transaktionen synchron bleiben, sodass ich mich nicht auf sicherheitsbasierte Ansätze verlassen muss, um dies zu gewährleisten. Andererseits kann ich nicht erzwingen, dass Salden nicht mehr negativ sind, da Ansichten - auch indizierte Ansichten - keineCHECK
Einschränkungen aufweisen können. (Unterstützt von Denny .)Haben Sie nur eine
transactions
Tabelle, aber mit einer zusätzlichen Spalte, um den Saldo direkt nach der Ausführung dieser Transaktion zu speichern. Somit enthält der letzte Transaktionsdatensatz für einen Benutzer und eine Währung auch den aktuellen Kontostand. (Vorgeschlagen von Andrew ; von Garik vorgeschlagene Variante .)
Als ich dieses Problem zum ersten Mal ansprach, las ich diese beiden Diskussionen und entschied mich für eine Option 2
. Als Referenz können Sie hier eine Bare-Bones-Implementierung sehen .
Haben Sie eine solche Datenbank mit einem hohen Lastprofil entworfen oder verwaltet? Was war Ihre Lösung für dieses Problem?
Glaubst du, ich habe die richtige Wahl getroffen? Was sollte ich beachten?
Ich weiß beispielsweise, dass Schemaänderungen an der
transactions
Tabelle eine Neuerstellung derbalances
Ansicht erfordern . Selbst wenn ich Transaktionen archiviere, um die Datenbank klein zu halten (z. B. indem ich sie an einen anderen Ort verschiebe und durch Zusammenfassungstransaktionen ersetze), bedeutet die Neuerstellung der Ansicht aus zig Millionen Transaktionen mit jeder Schemaaktualisierung wahrscheinlich eine erheblich längere Ausfallzeit pro Bereitstellung.Wie kann ich garantieren, dass kein Saldo negativ ist, wenn die indizierte Ansicht der richtige Weg ist?
Transaktionen archivieren:
Lassen Sie mich ein wenig auf die Archivierungstransaktionen und die "Zusammenfassungstransaktionen" eingehen, die ich oben erwähnt habe. Erstens ist in einem Hochlastsystem wie diesem eine regelmäßige Archivierung erforderlich. Ich möchte die Konsistenz zwischen Salden und ihren Transaktionsverläufen gewährleisten und gleichzeitig alte Transaktionen an einen anderen Ort verschieben. Dazu ersetze ich jeden Stapel archivierter Transaktionen durch eine Zusammenfassung ihrer Beträge pro Benutzer und Währung.
So zum Beispiel diese Liste von Transaktionen:
user_id currency_id amount is_summary
------------------------------------------------
3 1 10.60 0
3 1 -55.00 0
3 1 -12.12 0
wird archiviert und ersetzt durch:
user_id currency_id amount is_summary
------------------------------------------------
3 1 -56.52 1
Auf diese Weise behält ein Saldo mit archivierten Transaktionen eine vollständige und konsistente Transaktionshistorie bei.