it-swarm.com.de

Implementieren eines Subtyps eines Subtyps in einem Typ / Subtyp-Entwurfsmuster mit sich gegenseitig ausschließenden Unterklassen

Einführung

Damit diese Frage für zukünftige Leser nützlich ist, werde ich das generische Datenmodell verwenden, um das Problem zu veranschaulichen, mit dem ich konfrontiert bin.

Unser Datenmodell besteht aus 3 Entitäten, die als A, B und C gekennzeichnet werden sollen. Um die Dinge einfach zu halten, sind alle ihre Attribute vom Typ int.

Die Entität A hat folgende Attribute: D, E und X;

Die Entität B hat folgende Attribute: D, E und Y;

Die Entität C hat folgende Attribute: D und Z;

Da alle Entitäten das gemeinsame Attribut D haben, habe ich beschlossen, Typ/Subtyp Design anzuwenden.

Wichtig: Entitäten schließen sich gegenseitig aus! Dies bedeutet, dass die Entität entweder A oder B oder C ist.

Problem:

Entitäten A und B haben noch ein weiteres gemeinsames Attribut E, aber dieses Attribut ist in der Entität C nicht vorhanden.

Frage:

Ich möchte das oben beschriebene Merkmal verwenden, um mein Design nach Möglichkeit weiter zu optimieren.

Um ehrlich zu sein, habe ich keine Ahnung, wie ich das machen soll oder wo ich anfangen soll, daher dieser Beitrag.

Soweit diese Frage eine Fortsetzung von Ist meine Implementierung des Entwurfsmusters für Typ/Subtyp (für sich gegenseitig ausschließende Unterklassen) korrekt? , die selbst eine Fortsetzung von Weiß nicht, wie man transformiert variable Entität in relationale Tabelle , ich würde fragen: was genau versuchen Sie zu optimieren? Lager? Das Objektmodell? Komplexität der Abfrage? Leistung abfragen? Es gibt Kompromisse bei der Optimierung eines Aspekts gegenüber einem anderen, da Sie nicht alle Aspekte gleichzeitig optimieren können.

Ich stimme voll und ganz zu Remus 'Punkten in Bezug auf:

  • Jeder Ansatz hat Vor- und Nachteile (d. H. Den allgegenwärtigen Faktor "es hängt davon ab")
  • Die erste Priorität ist die Effizienz des Datenmodells (ein ineffizientes Datenmodell kann nicht durch sauberen und/oder effizienten App-Code korrigiert werden).

Sie haben jedoch die Wahl zwischen folgenden Optionen, die in der Reihenfolge der geringsten Normalisierung bis zur meisten Normalisierung angeordnet sind:

  • heraufstufen der Eigenschaft E in die Tabelle vom Basistyp
  • halten Sie es in mehreren Untertypen-Tabellen
  • vollständige Normalisierung von E auf eine neue, untergeordnete Unterklassentabelle auf derselben Ebene wie C, wobei A und B direkt Unterklassen sind von ( @ MDCCLs Antwort )

Schauen wir uns jede Option an:

Verschieben Sie die Eigenschaft E in die Tabelle vom Basistyp

PROs

  • Reduzierte Abfragekomplexität für Abfragen, die E, aber nicht X, Y oder Z benötigen.
  • Potenziell effizienter für Abfragen, die E, aber nicht X, Y oder Z benötigen (insbesondere aggregierte Abfragen), da kein JOIN vorhanden ist.
  • Möglichkeit, einen Index für (D, E) Zu erstellen (und wenn ja, möglicherweise einen gefilterten Index für (D, E), Wobei EntityType <> C, wenn eine solche Bedingung zulässig ist)

CONs

  • E kann nicht als NOT NULL Markiert werden.
  • Benötigen Sie zusätzliches CHECK CONSTRAINT Für die Basistabelle, um sicherzustellen, dass E IS NULL Wenn EntityType = C (obwohl dies kein großes Problem ist)
  • Benutzer des Datenmodells müssen darüber informiert werden, warum ENULL sein muss und sogar vollständig ignoriert werden sollte, wenn EntityType = C.
  • Etwas weniger effizient, wenn E ein Typ mit fester Länge ist, und ein großer Teil der Zeilen für den EntityType von C bestimmt ist (dh E daher ist es NULL), und, der weder die Option SPARSE in der Spalte noch die Datenkomprimierung im Clustered Index verwendet
  • Potenziell weniger effizient für Abfragen, die E nicht benötigen, da das Vorhandensein von E in der Basistyp-Tabelle die Größe jeder Zeile erhöht, was wiederum die Anzahl der Zeilen verringert, die passen können eine Datenseite. Dies hängt jedoch stark vom genauen Datentyp von E, dem FILLFACTOR, der Anzahl der Zeilen in der Basistabelle usw. ab.

Behalten Sie die Eigenschaft E in jeder Untertypentabelle bei

PROs

  • Saubereres Datenmodell (d. H. Sie müssen sich nicht darum kümmern, andere darüber zu informieren, warum die Spalte E in der Basistabelle nicht verwendet werden sollte, weil "sie wirklich nicht vorhanden ist").
  • Vermutlich ähnelt es eher dem Objektmodell
  • Kann die Spalte als NOT NULL Markieren, wenn dies eine erforderliche Eigenschaft der Entität ist
  • Es ist kein zusätzliches CHECK CONSTRAINT Für die Basistabelle erforderlich, um sicherzustellen, dass E IS NULL Bei EntityType = C (obwohl dies kein großer Gewinn ist).

CONs

  • Erfordert JOIN, um Tabellen zu untertypen, um diese Eigenschaft abzurufen
  • Möglicherweise etwas weniger effizient, wenn E aufgrund von JOIN benötigt wird, abhängig davon, wie viele Zeilen von A + B Sie haben, im Gegensatz zu wie vielen Zeilen von C es gibt.
  • Etwas schwieriger/komplexer für Operationen, die sich ausschließlich mit Entitäten A und B (und nichtC) befassen, da sie vom gleichen Typ sind ". Natürlich können Sie dies über eine Ansicht abstrahieren, die einen UNION ALL Zwischen einem SELECT der JOINed-Tabellen für A und einem anderen SELECT der JOINed-Tabellen ausführt für B. Dies reduziert die Komplexität von SELECT-Abfragen, ist jedoch für INSERT- und UPDATE-Abfragen nicht so hilfreich.
  • Abhängig von den spezifischen Abfragen und der Häufigkeit ihrer Ausführung kann dies eine potenzielle Ineffizienz sein, wenn ein Index für (D, E) Einer oder mehreren häufig verwendeten Abfragen wirklich hilft, da sie nicht zusammen indiziert werden können.

Normalisieren Sie E in die Zwischentabelle zwischen Basisklasse und A & B

(Bitte beachten Sie, dass mir @ MDCCLs Antwort ​​je nach den Umständen als praktikable Alternative gefällt. Das Folgende ist nicht als strenge Kritik an diesem Ansatz gedacht, sondern als Mittel, um eine Perspektive hinzuzufügen - meine Natürlich - indem Sie es im selben Kontext wie die beiden Optionen bewerten, die ich bereits vorgeschlagen hatte. Dadurch wird es einfacher zu klären, was ich als relativen Unterschied zwischen vollständiger Normalisierung und dem aktuellen Ansatz der partiellen Normalisierung sehe.)

PROs

  • das Datenmodell ist vollständig normalisiert (daran kann nichts von Natur aus falsch sein, da RDBMS dafür ausgelegt sind).
  • reduzierte Abfragekomplexität für Abfragen, die A und B benötigen, aber nicht C (d. h. keine Notwendigkeit für zwei Abfragen, die über UNION ALL verbunden sind)

CONs

  • etwas mehr Platz beansprucht (die Tabelle Bar dupliziert die ID, und es gibt eine neue Spalte, BarTypeCode) [vernachlässigbar, aber etwas zu beachten]
  • eine leichte Erhöhung der Abfragekomplexität als zusätzliches JOIN ist erforderlich, um entweder zu A oder B zu gelangen
  • vergrößerte Oberfläche zum Sperren, meistens auf INSERT (DELETE kann implizit durch Markieren von Fremdschlüsseln als ON CASCADE DELETE behandelt werden), da die Transaktion auf der Basis etwas länger offen gehalten wird. Klassentabelle (dh Foo) [vernachlässigbar, aber etwas zu beachten]
  • keine direkte Kenntnis des tatsächlichen Typs - A oder B - innerhalb der Basisklassentabelle, Foo; es kennt nur den Typ Br, der entweder A oder B sein kann:

    Das heißt, wenn Sie Abfragen über die allgemeinen Basisinformationen durchführen müssen, aber entweder nach Entitätstyp kategorisieren oder einen oder mehrere Entitätstypen herausfiltern müssen, verfügt die Basisklassentabelle nicht über genügend Informationen. In diesem Fall müssen Sie dies tun LEFT JOIN Die Tabelle Bar. Dies verringert auch die Effektivität der Indizierung der Spalte FooTypeCode.

  • kein konsistenter Ansatz für die Interaktion mit A & B vs C:

    Das heißt, wenn sich jede Entität direkt auf die Basisklassentabelle bezieht, sodass es immer nur einen JOIN gibt, um die vollständige Entität zu erhalten, kann jeder schneller und einfacher Vertrautheit mit der Arbeit mit dem Datenmodell aufbauen. Es wird einen gemeinsamen Ansatz für Abfragen/gespeicherte Prozeduren geben, der die Entwicklung beschleunigt und die Wahrscheinlichkeit von Fehlern verringert. Ein konsistenter Ansatz macht es auch schneller und einfacher, in Zukunft neue Untertypen hinzuzufügen.

  • möglicherweise weniger anpassungsfähig an Geschäftsregeln, die sich im Laufe der Zeit ändern:

    Das heißt, die Dinge ändern sich immer, und es ist ziemlich einfach, E in die Basisklassentabelle zu verschieben, wenn sie allen Untertypen gemeinsam ist. Es ist auch einfach genug, eine gemeinsame Eigenschaft in die Untertypen zu verschieben, wenn Änderungen in der Art der Entitäten dies zu einer lohnenden Änderung machen. Es ist einfach genug, einen Untertyp entweder in zwei Untertypen zu unterteilen (erstellen Sie einfach einen anderen SubTypeID -Wert) oder zwei oder mehr Untertypen zu einem zu kombinieren. Was wäre umgekehrt, wenn E später eine gemeinsame Eigenschaft aller Untertypen würde? Dann wäre die Zwischenschicht der Tabelle Bar bedeutungslos, und die zusätzliche Komplexität wäre es nicht wert. Natürlich ist es unmöglich zu wissen, ob eine solche Änderung in 5 oder sogar 10 Jahren eintreten würde, daher ist die Tabelle Bar weder unbedingt noch sehr wahrscheinlich. eine schlechte Idee (weshalb ich " möglicherweise weniger anpassungsfähig sagte"). Dies sind nur zu berücksichtigende Punkte; Es ist ein Glücksspiel in beide Richtungen.

  • möglicherweise unangemessene Gruppierung:

    Nur weil die Eigenschaft E von den Entitätstypen A und B gemeinsam genutzt wird, bedeutet dies nicht, dass A und Bshould zusammen gruppiert werden. Nur weil die Dinge gleich "aussehen" (d. H. Dieselben Eigenschaften), heißt das nicht, dass sie gleich sind.

Zusammenfassung

Genau wie bei der Entscheidung, ob/wann eine Denormalisierung durchgeführt werden soll, hängt die bestmögliche Herangehensweise an diese besondere Situation davon ab, die folgenden Aspekte der Verwendung des Datenmodells zu berücksichtigen und sicherzustellen, dass der Nutzen die Kosten überwiegt:

  • wie viele Zeilen werden Sie für jeden EntityType haben (schauen Sie mindestens 5 Jahre später unter der Annahme eines überdurchschnittlichen Wachstums)?
  • wie viele GB wird jede dieser Tabellen (Basistyp und Untertypen) in 5 Jahren haben?
  • welcher spezifische Datentyp ist die Eigenschaft E
  • ist es nur eine Eigenschaft oder gibt es einige oder sogar mehrere Eigenschaften?
  • für welche Abfragen benötigen Sie E und wie oft werden sie ausgeführt?
  • welche Abfragen Sie benötigen, die nicht E benötigen, und wie oft sie ausgeführt werden

Ich glaube, ich neige dazu, E standardmäßig in den separaten Untertyp-Tabellen zu belassen, da es zumindest "sauberer" ist. Ich würde in Betracht ziehen, E in die Tabelle vom Basistyp zu verschieben. IF: Die meisten Zeilen waren nicht für EntityType von C; und die Anzahl der Zeilen war mindestens in Millionen; und Ich habe Abfragen, die E benötigten, und/oder die Abfragen, die von einem Index für (D, E) profitieren würden, entweder sehr häufig ausgeführt und/oder genügend Systemressourcen erfordern, so dass der Index die gesamte Ressourcennutzung verringert oder zumindest einen Anstieg des Ressourcenverbrauchs verhindert, der über akzeptable Werte hinausgeht oder lange genug anhält, um eine übermäßige Blockierung und/oder eine Erhöhung der Deadlocks zu verursachen.


[~ # ~] Update [~ # ~]

O.P. kommentierte diese Antwort ​​dass:

Meine Arbeitgeber haben die Geschäftslogik geändert und E insgesamt entfernt!

Diese Änderung ist besonders wichtig, da genau das, was ich vorhergesagt habe, im Unterabschnitt "CONs" der Tabelle "Normalize E out to intermediary Table zwischen Basisklasse und A & B "Abschnitt oben (6. Aufzählungspunkt). Das spezifische Problem ist, wie einfach/schwierig es ist, das Datenmodell umzugestalten, wenn solche Änderungen eintreten (und das tun sie immer). Einige werden argumentieren, dass jedes Datenmodell überarbeitet/geändert werden kann. Beginnen Sie also mit dem Ideal. Aber während es wahr ist auf technischer Ebene, dass alles umgestaltet werden kann, ist die Realität der Situation eine Frage des Maßstabs.

Ressourcen sind nicht unendlich, nicht nur CPU/Disk/RAM, sondern auch Entwicklungsressourcen: Zeit und Geld. Unternehmen setzen ständig Prioritäten für Projekte, da diese Ressourcen sehr begrenzt sind. Und ziemlich oft (zumindest meiner Erfahrung nach) werden Projekte zur Steigerung der Effizienz (sowohl die Systemleistung als auch die schnellere Entwicklung/weniger Fehler) vor Projekten priorisiert, die die Funktionalität erhöhen. Während es für uns Techniker frustrierend ist, weil wir die langfristigen Vorteile von Refactoring-Projekten verstehen, ist es nur die Natur des Geschäfts, dass es den weniger technischen Geschäftsleuten leichter fällt, die direkte Beziehung zwischen neuer Funktionalität und neuer zu erkennen Einnahmen. Darauf kommt es an: "Wir werden zurückkommen, um das später zu beheben." == "Dieses Problem wird wahrscheinlich für die nächsten 5 - 10 Jahre da sein, weil wir fast immer wichtigere Dinge haben werden, an denen wir arbeiten müssen (ironischerweise wie z die Support-Fälle, die immer wieder auftauchen, weil wir sie noch nicht behoben haben) ".

In diesem Sinne, wenn die Größe der Daten so klein ist, dass Änderungen sehr abfragbar sind, und/oder Sie ein Wartungsfenster haben, das lang genug ist, um nicht nur die Änderungen vorzunehmen, sondern auch ein Rollback durchzuführen, wenn etwas passiert falsch, dann könnte das Normalisieren von E auf eine Zwischentabelle zwischen der Basisklassentabelle und den Unterklassentabellen A & B funktionieren (obwohl Sie immer noch keine haben direkte Kenntnis des spezifischen Typs (A oder B) in der Basisklassentabelle). ABER wenn Sie Hunderte Millionen Zeilen in diesen Tabellen haben und eine unglaubliche Menge an Code, der auf die Tabellen verweist (Code, der getestet werden muss, wenn Änderungen vorgenommen werden), lohnt es sich normalerweise, pragmatischer als idealistisch zu sein. Und mit dieser Umgebung musste ich mich jahrelang auseinandersetzen: 987 Millionen Zeilen und 615 GB in der Basisklassentabelle, verteilt auf 18 Server. Und so viel Code traf diese Tabellen (Basisklassen- und Unterklassen-Tabellen), dass es - hauptsächlich vom Management, manchmal aber auch vom Rest des Teams - großen Widerstand gab, Änderungen aufgrund des Entwicklungsaufwands vorzunehmen QS-Ressourcen, die zugewiesen werden müssten.

Der "beste" Ansatz kann also wiederum nur von Situation zu Situation bestimmt werden: Sie müssen Ihr System kennen (dh wie viele Daten und wie sich die Tabellen und der Code alle beziehen), wie das Refactoring durchgeführt werden kann und die Personen mit denen Sie zusammenarbeiten (Ihr Team und möglicherweise das Management - können Sie das Buy-In für ein solches Projekt erhalten?). Es gibt einige Änderungen, die ich seit 1 - 2 Jahren erwähnt und geplant habe und die mehrere Sprints/Releases durchgeführt haben, um vielleicht 85% davon umzusetzen. Wenn Sie jedoch nur <1 Million Zeilen und nicht viel Code an diese Tabellen gebunden haben, können Sie wahrscheinlich auf der idealeren/"reineren" Seite der Dinge beginnen.

Denken Sie daran, egal welchen Weg Sie wählen, achten Sie mindestens darauf, wie dieses Modell in den nächsten 2 Jahren funktioniert (wenn möglich). Achten Sie darauf, was funktioniert hat und was Schmerzen verursacht hat, auch wenn es zu dieser Zeit die beste Idee war (was bedeutet, dass Sie sich auch erlauben müssen, Fehler zu akzeptieren - das tun wir alle -, damit Sie die Schmerzpunkte ehrlich bewerten können ). Und achten Sie auf warum bestimmte Entscheidungen haben funktioniert oder nicht, damit Sie Entscheidungen treffen können, die wahrscheinlicher beim nächsten Mal "besser" sind :-) .

6
Solomon Rutzky

Laut Martin Fowler gibt es drei Ansätze für das Problem der Tabellenvererbung:

  • Single Table Inheritance : Eine Tabelle repräsentiert alle Typen. Nicht verwendete Attribute sind NULL.
  • Concrete Table Inheritance : Eine Tabelle pro Betontyp, jede Tabellenspalte für jedes Attribut des Typs. Keine Beziehung zwischen Tabellen.
  • Vererbung von Klassentabellen : Eine Tabelle pro Typ, jede Tabelle hat Attribute nur für neue, nicht vererbte Attribute. Tabellen sind miteinander verknüpft und spiegeln die tatsächliche Typvererbungshierarchie wider.

Sie können mit diesen als Ausgangspunkt beginnen, um nach Vor- und Nachteilen für jeden Ansatz zu suchen. Der Kern davon ist, dass alle Ansätze große Nachteile haben und keine einen überwältigenden Vorteil haben. Besser bekannt als Objektrelationale Impedanzfehlanpassung , dieses Problem muss noch gefunden werden.

Persönlich finde ich, dass die Art der Probleme, zu denen ein schlechtes relationales Design führen kann, um Größenordnungen schwerwiegender sind als die Art von Problemen, die sich aus einem schlechten Typ Design ergeben . Schlechtes Datenbankdesign führt zu langsamen Abfragen, Aktualisierungsanomalien, Datengrößenexplosion, Deadlocks und nicht reagierenden Apps und zehn bis hundert Gigabyte Daten, die im falschen Format versenkt wurden. Schlechtes Design führt zu einer schwierigen Wartung und Aktualisierung Code, nicht zur Laufzeit. Daher übertrifft in meinem Buch das korrekte relationale Design jedes OO Typ Reinheit immer und immer und immer wieder.

18
Remus Rusanu

Nach meiner Interpretation Ihrer Spezifikationen möchten Sie eine Methode finden, um zwei verschiedene (aber verbunden) Supertyp-Subtyp Strukturen zu implementieren.

Um einen Ansatz zur Erreichung der oben genannten Aufgabe aufzuzeigen, werde ich dem fraglichen Szenario die beiden klassischen Entitätstypen hypothetisch hinzufügen, die als Foo und Bar, auf die ich unten näher eingehen werde.

Geschäftsregeln

Hier sind einige Aussagen, die mir helfen, ein logisches Modell zu erstellen:

  • A Foo is either one Bar or one C
  • A Foo is categorized by one FooType
  • A Bar is either one A or one C
  • A Bar is classified by one BarType

Logisches Modell

Und dann die resultierende IDEF1X [1]  Das logische Modell ist in Abbildung 1 dargestellt (und Sie können es auch als PDF von Dropbox herunterladen):

Figure 1 - Hypothetical Supertype-Subtype Relationships Data Model

Der Foo und Bar Zusatz

Ich habe Foo und Bar nicht hinzugefügt, um das Modell besser aussehen zu lassen, sondern um es ausdrucksvoller zu machen. Ich halte sie aus folgenden Gründen für wichtig:

  • Da A und B das Attribut E gemeinsam haben, weist diese Funktion vor darauf hin, dass es sich um Subentitätstypen eines bestimmten (aber) handelt verwandte) Art von Konzept, Ereignis, Person, Messung usw. , die ich mit Hilfe des Superentitätstyps Bar dargestellt habe, der wiederum ein Subentitätstyp von Foo ist, der das Attribut D oben auf enthält Die Hierarchie.

  • Da C nur ein Attribut mit den übrigen diskutierten Entitätstypen teilt, dh D, ist dieser Aspekt unterstellt, dass es sich um einen Subentitätstyp handelt einer anderen Art von Konzept, Ereignis, Person, Messung usw. Also habe ich diesen Umstand anhand des Superentitätstyps Foo dargestellt.

Dies sind jedoch nur Annahmen, und da eine relationale Datenbank die Semantik eines bestimmten Geschäftskontexts genau widerspiegeln soll, müssen Sie alle Dinge von Interesse identifizieren und klassifizieren in Ihrer spezifischen Domain, damit Sie genau mehr Bedeutung erfassen können.

Wichtige Faktoren in der Entwurfsphase

Es ist sehr nützlich, sich der Tatsache bewusst zu sein, dass ein exklusiver Supertyp-Subtyp-Cluster, abgesehen von der Terminologie, eine gewöhnliche Beziehung ist. Beschreiben wir die Situation folgendermaßen:

  • Jedes exklusive Superentitätstyp Vorkommen bezieht sich nur auf ein Subentitätstyp Komplement.

Somit besteht in diesen Fällen eine Entsprechung (oder Kardinalität) von eins zu eins (1: 1).

Wie Sie aus Ihren vorhergehenden Beiträgen wissen, spielt das Attribut Diskriminator (Spalte, wenn implementiert) beim Erstellen einer Assoziation dieser Art eine herausragende Rolle, da es anzeigt die richtige Subtyp-Instanz, mit der der Supertyp verbunden ist. Die Migration des PRIMARY KEY von (i) dem Supertyp zu (ii) den Subtypen ist ebenfalls von größter Bedeutung.

Konkrete DDL-Struktur

Und dann habe ich eine DDL-Struktur geschrieben, die auf dem oben dargestellten logischen Modell basiert:

CREATE TABLE FooType -- Look-up table.
(
    FooTypeCode     CHAR(2)  NOT NULL,
    Description     CHAR(90) NOT NULL, 
    CreatedDateTime DATETIME NOT NULL,
    CONSTRAINT PK_FooType             PRIMARY KEY (FooTypeCode),
    CONSTRAINT AK_FooType_Description UNIQUE      (Description)
);

CREATE TABLE Foo -- Supertype
(
    FooId           INT      NOT NULL, -- This PK migrates (1) to ‘Bar’ as ‘BarId’, (2) to ‘A’ as ‘AId’, (3) to ‘B’ as ‘BId’, and (4) to ‘C’ as ‘CId’.
    FooTypeCode     CHAR(2)  NOT NULL, -- Discriminator column.
    D               INT      NOT NULL, -- Column that applies to ‘Bar’ (and therefore to ‘A’ and ‘B’) and ‘C’.
    CreatedDateTime DATETIME NOT NULL,
    CONSTRAINT PK_Foo                 PRIMARY KEY (FooId),
    CONSTRAINT FK_from_Foo_to_FooType FOREIGN KEY (FooTypeCode)
        REFERENCES FooType (FooTypeCode)
);

CREATE TABLE BarType -- Look-up table.
(
    BarTypeCode CHAR(1)  NOT NULL,  
    Description CHAR(90) NOT NULL,  
    CONSTRAINT PK_BarType             PRIMARY KEY (BarTypeCode),
    CONSTRAINT AK_BarType_Description UNIQUE      (Description)
);

CREATE TABLE Bar -- Subtype of ‘Foo’.
(
    BarId       INT     NOT NULL, -- PK and FK.
    BarTypeCode CHAR(1) NOT NULL, -- Discriminator column. 
    E           INT     NOT NULL, -- Column that applies to ‘A’ and ‘B’.
    CONSTRAINT PK_Bar             PRIMARY KEY (BarId),
    CONSTRAINT FK_from_Bar_to_Foo FOREIGN KEY (BarId)
        REFERENCES Foo (FooId),
    CONSTRAINT FK_from_Bar_to_BarType FOREIGN KEY (BarTypeCode)
        REFERENCES BarType (BarTypeCode)    
);

CREATE TABLE A -- Subtype of ‘Bar’.
(
    AId INT NOT NULL, -- PK and FK.
    X   INT NOT NULL, -- Particular column.  
    CONSTRAINT PK_A             PRIMARY KEY (AId),
    CONSTRAINT FK_from_A_to_Bar FOREIGN KEY (AId)
        REFERENCES Bar (BarId)  
);

CREATE TABLE B -- (1) Subtype of ‘Bar’ and (2) supertype of ‘A’ and ‘B’.
(
    BId INT NOT NULL, -- PK and FK.
    Y   INT NOT NULL, -- Particular column.  
    CONSTRAINT PK_B             PRIMARY KEY (BId),
    CONSTRAINT FK_from_B_to_Bar FOREIGN KEY (BId)
        REFERENCES Bar (BarId)  
);

CREATE TABLE C -- Subtype of ‘Foo’.
(
    CId INT NOT NULL, -- PK and FK.
    Z   INT NOT NULL, -- Particular column.  
    CONSTRAINT PK_C             PRIMARY KEY (CId),
    CONSTRAINT FK_from_C_to_Foo FOREIGN KEY (FooId)
        REFERENCES Foo (FooId)  
);

Mit dieser Struktur vermeiden Sie die Speicherung von NULL-Markierungen in Ihren Basistabellen (oder Beziehungen ), was zu Mehrdeutigkeiten in Ihrer Datenbank führen würde.

Integrität, Konsistenz und andere Überlegungen

Sobald Sie Ihre Datenbank implementiert haben, müssen Sie sicherstellen, dass (a) jede exklusive Supertyp Zeile immer durch das entsprechende Subtyp Gegenstück ergänzt wird und dies wiederum garantiert dass (b) eine solche Zeile Subtyp mit dem Wert kompatibel ist, der in der Spalte Supertyp Diskriminator enthalten ist. Daher ist es sehr praktisch, ACID TRANSACTIONS zu verwenden, um sicherzustellen, dass diese Bedingungen in Ihrer Datenbank erfüllt sind.

Sie sollten die logische Solidität, Selbstdarstellung und Genauigkeit Ihrer Datenbank nicht aufgeben. Dies sind Aspekte, die Ihre Datenbank entschieden solider machen.

Die beiden zuvor veröffentlichten Antworten enthalten bereits relevante Punkte, die beim Entwerfen, Erstellen und Verwalten Ihrer Datenbank und ihrer Anwendungsprogramme unbedingt berücksichtigt werden sollten.

Abrufen von Daten über VIEW-Definitionen

Sie können einige Ansichten einrichten, die kombinieren Spalten der verschiedenen Supertyp-Subtyp Gruppen, so dass Sie die vorliegenden Daten abrufen können, ohne z notwendige JOIN-Klauseln jedes Mal. Auf diese Weise können Sie mit Leichtigkeit direkt AUS DER ANSICHT (eine abgeleitete Beziehung oder Tabelle ) von Interesse AUSWÄHLEN.

Wie Sie sehen können, war "Ted" Codd zweifellos ein Genie. Die Werkzeuge, die er hinterlassen hat, sind ziemlich stark und elegant und natürlich gut miteinander integriert.

Ähnliche Resourcen

Wenn Sie eine umfangreiche Datenbank analysieren möchten, die Supertyp-Subtyp-Beziehungen umfasst, finden Sie die von @ PerformanceDBA vorgeschlagenen außergewöhnlichen Antworten auf die folgenden Fragen zum Stapelüberlauf von Wert:


Hinweis

1. Integrationsdefinition für die Informationsmodellierung ( IDEF1X ) ist eine sehr empfehlenswerte Datenmodellierungstechnik, die im Dezember 1993 als Standard von der Nationales Institut für Standards und Technologie der Vereinigten Staaten ( [~ # ~] nist [~ # ~] ). Es basiert fest auf (a) dem frühen theoretischen Material, das von Dr. E. F. Codd verfasst wurde; on (b) the Entity-Relationship -Ansicht von Daten, entwickelt von Dr. P. P. Chen ; und auch auf (c) der Logical Database Design Technique, erstellt von Robert G. Brown. Es ist erwähnenswert, dass IDEF1X über eine Logik erster Ordnung formalisiert wurde.

6
MDCCL