Generisches Datenbank-Tabellen-Design

8

Ich versuche nur, den besten Weg zu finden, meine Tabelle für das folgende Szenario zu entwerfen:

Ich habe mehrere Bereiche in meinem System (Dokumente, Projekte, Gruppen und Clients) und für jede dieser können Kommentare protokolliert werden.

Meine Frage ist, sollte ich eine Tabelle wie folgt haben:

%Vor%

Wo nur eine der IDs Daten hat und der Rest wird NULL sein oder sollte ich eine separate CommentType-Tabelle haben und meine Kommentartabelle so haben:

%Vor%

Meine Meinung ist, dass Option 2 aus Sicht der Indexierung effizienter wäre. Ist das korrekt?

    
Gazeth 16.06.2010, 16:21
quelle

10 Antworten

5

Lesen Sie bei der Datenbanknormalisierung nach.

Nullen in der Art, wie Sie beschreiben, wären ein großer Hinweis darauf, dass die Datenbank nicht richtig entworfen wurde.

Sie müssen alle Ihre Tabellen aufteilen, so dass die darin enthaltenen Daten vollständig normalisiert sind. Dadurch sparen Sie viel Zeit auf der ganzen Linie und es ist viel besser, sich an die Gewohnheit zu gewöhnen / p>     

Tom Gullen 16.06.2010 16:24
quelle
3

Aus der Perspektive eines Fremdschlüssels ist das erste Beispiel besser, da Sie für eine Spalte mehrere Fremdschlüsseleinschränkungen verwenden können, die Daten jedoch in allen diesen Referenzen vorhanden sein müssen. Es ist auch flexibler, wenn sich die Geschäftsregeln ändern.

    
OMG Ponies 16.06.2010 16:24
quelle
3

Um von @OMG Ponies 'Antwort fortzufahren, beschreiben Sie in Das zweite Beispiel wird als Polymorphe Assoziation bezeichnet, wobei der Fremdschlüssel ResourceID auf Zeilen in mehr als einer Tabelle verweisen kann. In SQL-Datenbanken kann eine Fremdschlüsseleinschränkung jedoch nur genau eine Tabelle referenzieren. Die Datenbank kann den Fremdschlüssel nicht entsprechend dem Wert in CommentTypeID erzwingen.

Möglicherweise möchten Sie den folgenden Stack Overflow-Post für eine Lösung ausprobieren, um dieses Problem anzugehen:

Daniel Vassallo 16.06.2010 16:25
quelle
3

Option 2 ist nicht eine gute Lösung für eine relationale Datenbank. Es heißt polymorphe Assoziationen (wie von @ Daniel Vassallo erwähnt) und bricht die fundamentale Definition einer Relation.

Angenommen, Sie haben eine ResourceId von 1234 in zwei verschiedenen Zeilen. Stellen diese die gleiche Ressource dar? Es hängt davon ab, ob die CommentTypeId in diesen beiden Zeilen identisch ist. Dies verstößt gegen das Konzept eines -Typs in einer Relation. Siehe SQL und Relationale Theorie von C. J. Date für weitere Details.

Ein weiterer Hinweis darauf, dass es sich um ein defektes Design handelt, besteht darin, dass Sie keine Fremdschlüsseleinschränkung für ResourceId deklarieren können, da es auf eine von mehreren Tabellen verweisen könnte. Wenn Sie versuchen, die referenzielle Integrität mithilfe von Triggern oder ähnlichem zu erzwingen, überschreiben Sie den Trigger jedes Mal, wenn Sie eine neue Art von kommentarischer Ressource hinzufügen.

Ich würde das mit der Lösung lösen, die @mdma kurz erwähnt (aber dann ignoriert):

%Vor%

Nun hat jeder Ressourcentyp eine eigene Tabelle, aber der serielle Primärschlüssel wird eindeutig durch Commentable zugewiesen. Ein bestimmter Primärschlüsselwert kann nur von einem Ressourcentyp verwendet werden.

%Vor%

Now Comments reference Kommentierbare Ressourcen, mit referenzieller Integrität erzwungen. Ein bestimmter Kommentar kann nur auf einen Ressourcentyp verweisen. Es gibt keine Möglichkeit für Anomalien oder widersprüchliche Ressourcen-IDs.

Ich behandle mehr über polymorphe Assoziationen in meiner Präsentation Praktische objektorientierte Modelle in SQL und mein Buch SQL Antipatterns .

    
Bill Karwin 16.06.2010 17:05
quelle
2

Der erste Ansatz ist nicht großartig, da er ziemlich denormalisiert ist. Jedes Mal, wenn Sie einen neuen Entitätstyp hinzufügen, müssen Sie die Tabelle aktualisieren. Es könnte besser sein, dies zu einem Attribut des Dokuments zu machen - z. Speichern Sie den Kommentar in der Dokumententabelle inline.

Damit die Methode ResourceID mit referenzieller Integrität arbeiten kann, müssen Sie eine Resource -Tabelle und einen ResourceID -Frontschlüssel in allen Entitäten von Document, Project usw. haben (oder eine Mapping-Tabelle verwenden) .) "ResourceID" zu einem Alleskönner zu machen, der eine documentID, projectID usw. sein kann, ist keine gute Lösung, da sie nicht für sinnvolle Indizierung oder Fremdschlüsseleinschränkungen verwendet werden kann.

Um zu normalisieren, müssen Sie die Kommentartabelle in eine Tabelle pro Ressourcentyp einfügen.

%Vor%

Wenn nur ein Kommentar zulässig ist, fügen Sie eine eindeutige Integritätsbedingung für den Fremdschlüssel für die Entität hinzu (DocumentID, ProjectID usw.). Dadurch wird sichergestellt, dass nur eine Zeile für das angegebene Element und damit nur ein Kommentar vorhanden ist. Sie können auch sicherstellen, dass Kommentare nicht mithilfe einer eindeutigen Einschränkung für die Kommentar-ID freigegeben werden.

EDIT: Interessanterweise ist dies fast parallel zu der normalisierten Implementierung von ResourceID - ersetzen Sie "Comment" im Tabellennamen, mit "Resource" und ändern "CommentID" zu "ResourceID" und Sie haben die Struktur benötigt, um eine ResourceID zuzuordnen mit jeder Ressource. Sie können dann eine einzelne Tabelle "ResourceComment" verwenden.

Wenn es andere Entitäten gibt, die mit einem Ressourcentyp verknüpft sind (z. B. Prüfdetails, Zugriffsrechte usw.), dann ist die Verwendung der Ressourcenzuordnungstabellen der richtige Weg, da Sie dies tun können Fügen Sie normalisierte Kommentare und andere ressourcenbezogene Entitäten hinzu.

    
mdma 16.06.2010 16:32
quelle
1

Ich würde mit keiner dieser Lösungen gehen. Abhängig von einigen Besonderheiten Ihrer Anforderungen könnten Sie mit einer Super-Typ-Tabelle gehen:

%Vor%

Wenn jedes Element nur einen Kommentar haben kann und Kommentare nicht geteilt werden (d. h. ein Kommentar kann nur zu einer Entität gehören), könnten Sie die Kommentare einfach in die Tabelle Commentable_Items schreiben. Andernfalls könnten Sie die Kommentare dieser Tabelle mit einem Fremdschlüssel verknüpfen.

Ich mag diesen Ansatz in Ihrem speziellen Fall allerdings nicht sehr, denn "Kommentare zu haben" reicht nicht aus, um Dinge in meinem Kopf zusammenzustellen.

Ich würde wahrscheinlich mit separaten Kommentartabellen gehen (vorausgesetzt, dass Sie mehrere Kommentare pro Element haben können - andernfalls setzen Sie sie einfach in Ihre Basistabellen). Wenn ein Kommentar zwischen mehreren Entitätstypen geteilt werden kann (d. H. Ein Dokument und ein Projekt können denselben Kommentar haben), dann haben Sie eine zentrale Kommentartabelle und mehrere Entity-Kommentar-Beziehungstabellen:

%Vor%

Wenn Sie Kommentare beispielsweise auf ein einzelnes Dokument beschränken möchten, können Sie einen eindeutigen Index (oder ändern Sie den Primärschlüssel) für die Kommentar-ID innerhalb dieser Verknüpfungstabelle hinzufügen.

Es sind all diese "kleinen" Entscheidungen, die die spezifischen PKs und FKs beeinflussen. Ich mag diesen Ansatz, weil jeder Tisch klar ist, was es ist. In Datenbanken ist das normalerweise besser als "generische" Tabellen / Lösungen.

    
Tom H 16.06.2010 17:56
quelle
0

Von den Optionen, die Sie geben, würde ich für Nummer 2 gehen.

    
Galwegian 16.06.2010 16:24
quelle
0

Option 2 ist ein guter Weg. Das Problem, das ich damit sehe, ist, dass Sie den Resoue-Schlüssel auf diesen Tisch legen. Jede der IDs aus den verschiedenen Ressourcen könnte dupliziert werden. Wenn Sie Ressourcen zu den Kommentaren hinzufügen, werden Sie höchstwahrscheinlich mit Kommentaren kommen, die nicht zu dieser bestimmten Ressource gehören. Dies würde als viel zu viele gelten. Ich würde denken, eine bessere Option wäre, Ihre Ressourcentabellen, die Kommentartabelle und dann Tabellen zu haben, die den Ressourcentyp und die Kommentartabelle referenzieren.

    
edgel1k 16.06.2010 16:34
quelle
0

Wenn Sie die gleichen Daten über alle Kommentare haben, unabhängig davon, worüber sie Kommentare sind, würde ich gegen die Erstellung mehrerer Kommentartabellen stimmen. Vielleicht ist ein Kommentar nur "Sache, worum es geht" und Text, aber wenn Sie jetzt keine anderen Daten haben, werden Sie wahrscheinlich: Datum der Eingabe des Kommentars, Benutzer-ID der Person, die es erstellt hat, usw. Mit mehreren Tabellen müssen alle diese Spaltendefinitionen für jede Tabelle wiederholen.

Wie bereits erwähnt, bedeutet die Verwendung eines einzelnen Referenzfelds, dass Sie keine Fremdschlüsseleinschränkung festlegen können. Das ist zu schade, aber es bricht nichts, es bedeutet nur, dass Sie die Validierung mit einem Trigger oder im Code durchführen müssen. Im Ernst, Joins werden schwierig. Sie können einfach sagen "aus Kommentar beitreten Dokument mit (Dokument-ID)". Sie benötigen einen komplexen Join basierend auf dem Wert des Typfeldes.

Während also die Felder mit mehreren Zeigern hässlich sind, tendiere ich zu denken, dass das der richtige Weg ist. Ich weiß, einige Db Leute sagen, dass es nie ein Null-Feld in einer Tabelle geben sollte, dass Sie es immer in eine andere Tabelle brechen sollten, um das zu verhindern, aber ich sehe keinen wirklichen Vorteil, dieser Regel zu folgen.

Ich persönlich wäre offen für weitere Diskussionen über Vor- und Nachteile.

    
Jay 16.06.2010 16:54
quelle
0

Pfandhaus-Anwendung:

Ich habe separate Tabellen für Darlehen, Kauf, Inventar & amp; Verkaufsvorgänge Jede Tabellenzeile wird mit den entsprechenden Kundenzeilen verknüpft:

%Vor%

Ich habe die vier Tabellen in einer Tabelle namens "transaction" konsolidiert, wobei eine Spalte:

transaction.trx_type char (1) {L = Darlehen, P = Kauf, I = Inventar, S = Verkauf}

Szenario:

Ein Kunde packt zunächst Ware, zahlt ein paar Zinszahlungen und entscheidet dann, dass er die Ware an das Pfandhaus verkaufen möchte, der die Waren dann in das Inventar legt und schließlich an einen anderen Kunden verkauft.

Ich habe eine generische Transaktionstabelle entworfen, in der zum Beispiel:

transaction.main_amount DECIMAL (7,2)

in einer Darlehenstransaktion hält den Pfandbetrag, in einem Kauf hält der Kaufpreis, in Inventar und Verkauf hält Verkaufspreis.

Dies ist eindeutig ein denormalisiertes Design, aber es hat die Programmierung viel einfacher und die Leistung verbessert. Jede Art von Transaktion kann jetzt von einem Bildschirm aus durchgeführt werden, ohne dass zu verschiedenen Tabellen gewechselt werden muss.

    
Frank R. 16.06.2010 23:12
quelle