Ich denke darüber nach, wie eine komplexe Struktur in einer SQL Server-Datenbank dargestellt werden kann.
Stellen Sie sich eine Anwendung vor, die Details einer Objektfamilie speichern muss, die einige Attribute gemeinsam haben, aber viele andere nicht gemeinsam haben. Zum Beispiel kann ein gewerbliches Versicherungspaket Haftpflicht-, Motor-, Sach- und Entschädigungsschutz in demselben Versicherungsdatensatz enthalten.
Es ist trivial, dies in C # usw. zu implementieren, da Sie eine Richtlinie mit einer Sammlung von Abschnitten erstellen können, wobei Abschnitt nach Bedarf für die verschiedenen Deckungsarten vererbt wird. Relationale Datenbanken scheinen dies jedoch nicht einfach zuzulassen.
Ich kann sehen, dass es zwei Hauptoptionen gibt:
Erstellen Sie eine Richtlinientabelle und dann eine Abschnittstabelle mit allen erforderlichen Feldern für alle möglichen Variationen, von denen die meisten null wären.
Erstellen Sie eine Richtlinientabelle und zahlreiche Abschnittstabellen, eine für jede Art von Deckung.
Diese beiden Alternativen scheinen unbefriedigend zu sein, insbesondere da Abfragen über alle Abschnitte hinweg geschrieben werden müssen, was zahlreiche Verknüpfungen oder zahlreiche Nullprüfungen beinhalten würde.
Was ist die beste Vorgehensweise für dieses Szenario?
Antworten:
@ Bill Karwin beschreibt drei Vererbungsmodelle in seinem Buch SQL Antipatterns , wenn er Lösungen für das Antipattern SQL Entity-Attribute-Value vorschlägt. Dies ist eine kurze Übersicht:
Vererbung einzelner Tabellen (auch Vererbung von Tabellen pro Hierarchie genannt):
Die Verwendung einer einzelnen Tabelle wie in Ihrer ersten Option ist wahrscheinlich das einfachste Design. Wie Sie bereits erwähnt haben, müssen viele subtypspezifische Attribute
NULL
in Zeilen, in denen diese Attribute nicht zutreffen , mit einem Wert versehen werden. Mit diesem Modell hätten Sie eine Richtlinientabelle, die ungefähr so aussehen würde:Das Design einfach zu halten ist ein Plus, aber die Hauptprobleme bei diesem Ansatz sind die folgenden:
Wenn Sie neue Untertypen hinzufügen möchten, müssen Sie die Tabelle ändern, um die Attribute zu berücksichtigen, die diese neuen Objekte beschreiben. Dies kann schnell problematisch werden, wenn Sie viele Untertypen haben oder wenn Sie regelmäßig Untertypen hinzufügen möchten.
Die Datenbank kann nicht erzwingen, welche Attribute zutreffen und welche nicht, da keine Metadaten vorhanden sind, um zu definieren, welche Attribute zu welchen Untertypen gehören.
Sie können auch keine
NOT NULL
Attribute eines Subtyps erzwingen , die obligatorisch sein sollten. Sie müssten dies in Ihrer Anwendung behandeln, was im Allgemeinen nicht ideal ist.Vererbung von Betontabellen:
Ein anderer Ansatz zur Bekämpfung der Vererbung besteht darin, für jeden Subtyp eine neue Tabelle zu erstellen und alle gemeinsamen Attribute in jeder Tabelle zu wiederholen. Beispielsweise:
Dieses Design löst im Wesentlichen die Probleme, die für die Einzeltabellenmethode identifiziert wurden:
Obligatorische Attribute können jetzt mit erzwungen werden
NOT NULL
.Das Hinzufügen eines neuen Untertyps erfordert das Hinzufügen einer neuen Tabelle, anstatt einer vorhandenen Spalte Spalten hinzuzufügen.
Es besteht auch kein Risiko, dass ein unangemessenes Attribut für einen bestimmten Subtyp festgelegt wird, z. B. das
vehicle_reg_no
Feld für eine Eigenschaftsrichtlinie.Das
type
Attribut ist nicht wie bei der Einzeltabellenmethode erforderlich . Der Typ wird jetzt durch die Metadaten definiert: den Tabellennamen.Dieses Modell hat jedoch auch einige Nachteile:
Die allgemeinen Attribute werden mit den subtypspezifischen Attributen gemischt, und es gibt keine einfache Möglichkeit, sie zu identifizieren. Die Datenbank wird es auch nicht wissen.
Beim Definieren der Tabellen müssten Sie die allgemeinen Attribute für jede Untertypentabelle wiederholen. Das ist definitiv nicht trocken .
Das Suchen nach allen Richtlinien unabhängig vom Subtyp wird schwierig und erfordert eine Reihe von
UNION
s.Auf diese Weise müssten Sie alle Richtlinien unabhängig vom Typ abfragen:
Beachten Sie, dass für das Hinzufügen neuer Untertypen die obige Abfrage mit einem zusätzlichen
UNION ALL
für jeden Untertyp geändert werden muss . Dies kann leicht zu Fehlern in Ihrer Anwendung führen, wenn dieser Vorgang vergessen wird.Vererbung von Klassentabellen (auch bekannt als Vererbung von Tabellen pro Typ):
Dies ist die Lösung, die @David in der anderen Antwort erwähnt . Sie erstellen eine einzelne Tabelle für Ihre Basisklasse, die alle allgemeinen Attribute enthält. Dann würden Sie für jeden Subtyp bestimmte Tabellen erstellen, deren Primärschlüssel auch als Fremdschlüssel für die Basistabelle dient. Beispiel:
Diese Lösung löst die in den beiden anderen Designs identifizierten Probleme:
Obligatorische Attribute können mit erzwungen werden
NOT NULL
.Das Hinzufügen eines neuen Untertyps erfordert das Hinzufügen einer neuen Tabelle, anstatt einer vorhandenen Spalte Spalten hinzuzufügen.
Kein Risiko, dass für einen bestimmten Subtyp ein unangemessenes Attribut festgelegt wird.
Das
type
Attribut ist nicht erforderlich .Jetzt werden die allgemeinen Attribute nicht mehr mit den subtypspezifischen Attributen gemischt.
Wir können endlich trocken bleiben. Es ist nicht erforderlich, die allgemeinen Attribute für jede Subtyp-Tabelle beim Erstellen der Tabellen zu wiederholen.
Das Verwalten eines automatischen Inkrementierens
id
für die Richtlinien wird einfacher, da dies von der Basistabelle verwaltet werden kann, anstatt dass jede Subtyp-Tabelle sie unabhängig generiert.Das Suchen nach allen Richtlinien unabhängig vom Subtyp wird jetzt sehr einfach: Keine
UNION
s erforderlich - nur aSELECT * FROM policies
.Ich halte den Klassentabellenansatz in den meisten Situationen für am besten geeignet.
Die Namen dieser drei Modelle stammen aus Martin Fowlers Buch Patterns of Enterprise Application Architecture .
quelle
Die dritte Option besteht darin, eine "Policy" -Tabelle und dann eine "SectionsMain" -Tabelle zu erstellen, in der alle Felder gespeichert sind, die für die verschiedenen Abschnittsarten gleich sind. Erstellen Sie dann für jeden Abschnittstyp andere Tabellen, die nur die Felder enthalten, die nicht gemeinsam sind.
Die Entscheidung, welches am besten ist, hängt hauptsächlich davon ab, wie viele Felder Sie haben und wie Sie Ihre SQL schreiben möchten. Sie würden alle arbeiten. Wenn Sie nur ein paar Felder haben, würde ich wahrscheinlich mit # 1 gehen. Mit "vielen" Feldern würde ich mich zu # 2 oder # 3 neigen.
quelle
Mit den bereitgestellten Informationen würde ich die Datenbank folgendermaßen modellieren:
POLITIK
VERBINDLICHKEITEN
EIGENSCHAFTEN
... und so weiter, weil ich erwarten würde, dass jedem Abschnitt der Richtlinie unterschiedliche Attribute zugeordnet sind. Andernfalls könnte es ein einziger seinen
SECTIONS
Tisch und zusätzlich zu dempolicy_id
, würde es sein ,section_type_code
...In beiden Fällen können Sie optionale Abschnitte pro Richtlinie unterstützen ...
Ich verstehe nicht, was Sie an diesem Ansatz als unbefriedigend empfinden. Auf diese Weise speichern Sie Daten, während Sie die referenzielle Integrität beibehalten und keine Daten duplizieren. Der Begriff ist "normalisiert" ...
Da SQL SET-basiert ist, ist es prozeduralen / OO-Programmierkonzepten eher fremd und erfordert Code für den Übergang von einem Bereich in den anderen. ORMs werden oft in Betracht gezogen, funktionieren jedoch in komplexen Systemen mit hohem Volumen nicht gut.
quelle
Wenn Sie bei der Daniel Vassallo-Lösung SQL Server 2016+ verwenden, gibt es außerdem eine andere Lösung, die ich in einigen Fällen ohne nennenswerten Leistungsverlust verwendet habe.
Sie können nur eine Tabelle mit nur dem gemeinsamen Feld erstellen und eine einzelne Spalte mit der JSON- Zeichenfolge hinzufügen , die alle subtypspezifischen Felder enthält.
Ich habe dieses Design für die Verwaltung der Vererbung getestet und freue mich sehr über die Flexibilität, die ich in der jeweiligen Anwendung verwenden kann.
quelle
Die andere Möglichkeit besteht darin, die
INHERITS
Komponente zu verwenden. Beispielsweise:Somit ist es möglich, eine Vererbung zwischen Tabellen zu definieren.
quelle
INHERITS
neben PostgreSQL ? MySQL zum Beispiel?Ich neige zu Methode 1 (einer einheitlichen Abschnittstabelle), um ganze Richtlinien mit all ihren Abschnitten effizient abzurufen (von denen ich annehme, dass Ihr System viel tun wird).
Außerdem weiß ich nicht, welche Version von SQL Server Sie verwenden, aber ab 2008 helfen Sparse Columns dabei, die Leistung in Situationen zu optimieren, in denen viele der Werte in einer Spalte NULL sind.
Letztendlich müssen Sie entscheiden, wie "ähnlich" die Richtlinienabschnitte sind. Wenn sie sich nicht wesentlich unterscheiden, denke ich, dass eine normalisierte Lösung mehr Probleme bereiten kann, als es wert ist ... aber nur Sie können diesen Anruf tätigen. :) :)
quelle
Alternativ können Sie Dokumentendatenbanken (z. B. MongoDB) verwenden, die native Datenstrukturen und Verschachtelungen nativ unterstützen.
quelle
Schauen Sie sich die Antwort an, die ich hier gegeben habe
Fließendes NHibernate-Eins-zu-Eins-Mapping mit synthetischen Schlüsseln
quelle