Designdebatte:Was sind gute Möglichkeiten, versionierte Objekte zu speichern und zu bearbeiten?[geschlossen]

StackOverflow https://stackoverflow.com/questions/11689

Frage

Ich halte dies bewusst zunächst recht vage.Ich suche mehr nach Diskussionen und nach wichtigen Themen als nach konkreten Antworten.

Ich bin gerade dabei, eine App zu entwerfen, die so etwas wie Portfoliomanagement macht.Das Design, das ich bisher habe, ist

  • Problem:ein Problem, das gelöst werden muss
  • Lösung:ein Lösungsvorschlag für ein oder mehrere Probleme
  • Beziehung:eine Beziehung zwischen zwei Problemen, zwei Lösungen oder einem Problem und einer Lösung.Weiter unterteilt in:
    • Eltern-Kind – eine Art Kategorisierung/Baumhierarchie
    • Überlappung – der Grad, in dem zwei Lösungen oder zwei Probleme tatsächlich dasselbe Konzept ansprechen
    • Adressen – der Grad, in dem ein Problem eine Lösung anspricht

Meine Frage betrifft die zeitliche Natur dieser Dinge.Probleme tauchen auf und verschwinden dann.Lösungen haben ein voraussichtliches Lösungsdatum, das sich jedoch im Laufe der Entwicklung ändern kann.Der Grad einer Beziehung kann sich im Laufe der Zeit ändern, wenn sich Probleme und Lösungen entwickeln.

Also die Frage:Was ist das beste Design für die Versionierung dieser Dinge, damit ich sowohl eine aktuelle als auch eine historische Perspektive meines Portfolios erhalten kann?

Später:Vielleicht sollte ich diese Frage konkreter stellen, obwohl die Antwort von @Eric Beard einen Blick wert ist.

Ich habe drei Datenbankdesigns in Betracht gezogen.Ich werde genug von jedem zeigen, um seine Nachteile aufzuzeigen.Meine Frage ist:Was soll ich auswählen, oder fällt Ihnen etwas Besseres ein?

1:Probleme (und separat Lösungen) sind bei der Versionierung selbstreferenziell.

table problems
  int id | string name | text description | datetime created_at | int previous_version_id

  foreign key previous_version_id -> problems.id

Das ist problematisch, weil ich jedes Mal, wenn ich eine neue Version möchte, die gesamte Zeile duplizieren muss, auch diese lange description Spalte.

2:Erstellen Sie einen neuen Beziehungstyp:Ausführung.

table problems
  int id | string name | text description | datetime created_at

Dadurch wird die Beziehung einfach aus den Tabellen „Probleme“ und „Lösungen“ in die Tabelle „Beziehungen“ verschoben.Gleiches Duplikationsproblem, aber vielleicht etwas „sauberer“, da ich bereits ein abstraktes Beziehungskonzept habe.

3:Verwenden Sie eine eher Subversion-ähnliche Struktur.Verschieben Sie alle Problem- und Lösungsattribute in eine separate Tabelle und versionieren Sie sie.

table problems
  int id

table attributes
  int id | int thing_id | string thing_type | string name | string value | datetime created_at | int previous_version_id

  foreign key (thing_id, thing_type) -> problems.id or solutions.id
  foreign key previous_version_id -> attributes.id

Das bedeutet, dass ich zum Laden der aktuellen Version eines Problems oder einer Lösung alle Versionen des Attributs abrufen, sie nach Datum sortieren und dann die aktuellste verwenden muss.Das ist vielleicht nicht so schlimm.Was mir wirklich schlecht erscheint, ist, dass ich diese Attribute in der Datenbank nicht typisieren kann.Das value Die Spalte muss Freitext sein.Ich kann das machen name Spalte eine Referenz in eine separate attribute_names Tisch mit einem type Spalte, aber das ist nicht der Fall Gewalt den richtigen Typ in der attributes Tisch.

später noch:Antwort auf die Kommentare von @Eric Beard zu Fremdschlüsseln mit mehreren Tabellen:

Leider ist das, was ich beschrieben habe, simpel:Es gibt nur zwei Arten von Dingen (Probleme und Lösungen).Ich habe tatsächlich etwa 9 oder 10 verschiedene Arten von Dingen, also würde ich in Ihrer Strategie 9 oder 10 Spalten mit Fremdschlüsseln haben.Ich wollte die Einzeltabellenvererbung verwenden, aber die Dinge haben so wenig gemeinsam, dass dies der Fall wäre äußerst Es wäre verschwenderisch, sie in einer Tabelle zusammenzufassen.

War es hilfreich?

Lösung

Hmm, das klingt irgendwie nach dieser Seite...

Was das Datenbankdesign betrifft, könnten Sie ein Versionierungssystem wie SVN benötigen, bei dem Sie eigentlich nie Aktualisierungen durchführen, sondern nur (mit einer Versionsnummer) einfügen, wenn sich etwas ändert.Dies nennt man MVCC, Multi-Value Concurrency Control.Ein Wiki ist ein weiteres gutes Beispiel dafür.

Andere Tipps

@Gaius

foreign key (thing_id, thing_type) -> problems.id or solutions.id

Seien Sie vorsichtig mit solchen „multidirektionalen“ Fremdschlüsseln.Meine Erfahrung hat gezeigt, dass die Abfrageleistung erheblich beeinträchtigt wird, wenn Ihre Join-Bedingung den Typ überprüfen muss, bevor sie herausfindet, mit welcher Tabelle verknüpft werden soll.Es scheint nicht so elegant, aber nullwertig zu sein

problem_id and solution_id 

wird viel besser funktionieren.

Natürlich leidet auch die Abfrageleistung bei einem MVCC-Design, wenn Sie die Prüfung hinzufügen müssen, um die neueste Version eines Datensatzes zu erhalten.Der Nachteil besteht darin, dass Sie sich bei Aktualisierungen keine Sorgen über Konflikte machen müssen.

Wie denken Sie darüber:

Tischprobleme
int id | Zeichenfolge Name | Textbeschreibung | DateTime erstellt_at

Tabelle „problems_revisions“.
int Revision | int id | Zeichenfolge Name | Textbeschreibung | DateTime erstellt_at
Fremdschlüssel-ID -> Probleme.id

Vor Updates müssen Sie eine zusätzliche Einfügung in die Revisionstabelle durchführen.Diese zusätzliche Einlage geht zwar schnell, muss dafür aber bezahlt werden

  1. Effizienter Zugriff auf die aktuelle Version – Probleme wie gewohnt auswählen
  2. ein Schema, das intuitiv ist und der Realität nahe kommt, die Sie modellieren möchten
  3. Verknüpfungen zwischen Tabellen in Ihrem Schema bleiben effizient
  4. Wenn Sie eine Revisionsnummer pro Geschäftstransaktion verwenden, können Sie Tabellendatensätze so versionieren, wie SVN dies für Dateien tut.

Ich nehme an, das gibt es

Option 4:der Hybrid

Verschieben Sie die allgemeinen Dingattribute in eine Tabelle mit einfacher Vererbung und fügen Sie dann ein hinzu custom_attributes Tisch.Dies vereinfacht die Verwendung von Fremdschlüsseln, reduziert die Duplizierung und ermöglicht Flexibilität.Es löst nicht die Probleme der Typsicherheit für die zusätzlichen Attribute.Es erhöht auch die Komplexität, da es jetzt zwei Möglichkeiten für ein Ding gibt, ein Attribut zu haben.

Wenn description und andere große Felder bleiben in der Things-Tabelle, das Problem des Duplizierungsraums wird dadurch jedoch auch nicht gelöst.

table things
  int id | int type | string name | text description | datetime created_at | other common fields...
  foreign key type -> thing_types.id

table custom_attributes
  int id | int thing_id | string name | string value
  foreign key thing_id -> things.id

Es ist eine gute Idee, eine Datenstruktur zu wählen, die eine einfache Beantwortung häufig gestellter Fragen an das Modell ermöglicht.Höchstwahrscheinlich sind Sie die meiste Zeit an der aktuellen Position interessiert.Gelegentlich möchten Sie bei bestimmten Problemen und Lösungen tiefer in die Historie eintauchen.

Ich hätte Tabellen für Problem, Lösung und Beziehung, die die aktuelle Position darstellen.Es gäbe auch eine problem_history, solution_history, usw. Tabelle.Dabei handelt es sich um untergeordnete Problemtabellen, die aber auch zusätzliche Spalten für enthalten VersionNumber Und EffectiveDate.Der Schlüssel wäre (ProblemId, VersionNumber).

Wenn Sie ein Problem aktualisieren, schreiben Sie die alten Werte in das problem_history Tisch.Daher sind Zeitpunktabfragen möglich, da Sie die auswählen können problem_history Datensatz, der zu einem bestimmten Datum gültig ist.

Wo ich das schon einmal gemacht habe, habe ich auch eine Ansicht auf UNION erstellt problem Und problem_history da dies manchmal bei verschiedenen Abfragen nützlich ist.

Option 1 macht es schwierig, die aktuelle Situation abzufragen, da alle Ihre historischen Daten mit Ihren aktuellen Daten vermischt werden.

Option 3 wird sich negativ auf die Abfrageleistung auswirken und beim Programmieren unangenehm sein, da Sie auf viele Zeilen für eine eigentlich einfache Abfrage zugreifen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top