Mein Hintergrund liegt eher in der Webprogrammierung als in der Datenbankverwaltung. Bitte korrigieren Sie mich, wenn ich hier die falsche Terminologie verwende. Ich versuche herauszufinden, wie ich die Datenbank am besten für eine Anwendung entwerfen kann, die ich codieren werde.
Die Situation: Ich habe Berichte in einer Tabelle und Empfehlungen in einer anderen Tabelle. Jeder Bericht kann viele Empfehlungen enthalten. Ich habe auch eine separate Tabelle für Schlüsselwörter (um das Tagging zu implementieren). Ich möchte jedoch nur einen Satz von Schlüsselwörtern haben, der sowohl auf Berichte als auch auf Empfehlungen angewendet wird, sodass Sie bei der Suche nach Schlüsselwörtern Berichte und Empfehlungen als Ergebnisse erhalten.
Hier ist die Struktur, mit der ich angefangen habe:
Reports
----------
ReportID
ReportName
Recommendations
----------
RecommendationID
RecommendationName
ReportID (foreign key)
Keywords
----------
KeywordID
KeywordName
ObjectKeywords
----------
KeywordID (foreign key)
ReportID (foreign key)
RecommendationID (foreign key)
Instinktiv bin ich der Meinung, dass dies nicht optimal ist und dass ich meine taggbaren Objekte von einem gemeinsamen übergeordneten Objekt erben und diesen übergeordneten Kommentar mit Tags versehen lassen sollte, was die folgende Struktur ergeben würde:
BaseObjects
----------
ObjectID (primary key)
ObjectType
Reports
----------
ObjectID_Report (foreign key)
ReportName
Recommendations
----------
ObjectID_Recommendation (foreign key)
RecommendationName
ObjectID_Report (foreign key)
Keywords
----------
KeywordID (primary key)
KeywordName
ObjectKeywords
----------
ObjectID (foreign key)
KeywordID (foreign key)
Soll ich mit dieser zweiten Struktur gehen? Vermisse ich hier wichtige Bedenken? Was sollte ich als nicht generischen Namen verwenden, um "Objekt" zu ersetzen, wenn ich mich für den zweiten Namen entscheide?
Aktualisieren:
Ich verwende SQL Server für dieses Projekt. Es ist eine interne Anwendung mit einer kleinen Anzahl nicht gleichzeitiger Benutzer, daher erwarte ich keine hohe Auslastung. In Bezug auf die Verwendung werden die Schlüsselwörter wahrscheinlich sparsam verwendet. Es ist so ziemlich nur für statistische Berichtszwecke. In diesem Sinne wirkt sich jede Lösung wahrscheinlich nur auf Entwickler aus, die dieses System später warten müssen ... aber ich dachte, es ist gut, bewährte Verfahren zu implementieren, wann immer ich kann. Danke für all den Einblick!
quelle
Antworten:
Das Problem mit Ihrem ersten Beispiel ist die Tri-Link-Tabelle. Ist es erforderlich, dass einer der Fremdschlüssel in Berichten oder Empfehlungen immer NULL ist, damit Schlüsselwörter nur auf die eine oder andere Weise verknüpft werden?
Im Fall Ihres zweiten Beispiels erfordert die Verknüpfung von der Basis zu den abgeleiteten Tabellen möglicherweise die Verwendung des Typselektors oder der LEFT JOINs, je nachdem, wie Sie dies tun.
Warum nicht einfach explizit machen und alle NULL- und LEFT-JOINs eliminieren?
Wenn Sie in diesem Szenario etwas anderes hinzufügen, das markiert werden muss, fügen Sie einfach die Entitätstabelle und die Verknüpfungstabelle hinzu.
Dann sehen Ihre Suchergebnisse folgendermaßen aus (siehe, es wird noch eine Typauswahl durchgeführt und sie werden auf der Ebene der Objektergebnisse in Generika umgewandelt, wenn Sie eine einzelne Ergebnisliste wünschen):
Egal was passiert, irgendwo wird es eine Typauswahl und eine Art Verzweigung geben.
Wenn Sie sich ansehen, wie Sie dies in Ihrer Option 1 tun würden, ist es ähnlich, aber entweder mit einer CASE-Anweisung oder LEFT JOINs und einer COALESCE. Wenn Sie Ihre Option 2 erweitern, indem mehr Dinge verknüpft werden, müssen Sie immer mehr LEFT JOINs hinzufügen, bei denen Dinge normalerweise NICHT gefunden werden (ein verknüpftes Objekt kann nur eine abgeleitete Tabelle haben, die gültig ist).
Ich glaube nicht, dass irgendetwas an Ihrer Option 2 grundlegend falsch ist, und Sie könnten es tatsächlich so aussehen lassen, als ob dieser Vorschlag unter Verwendung von Ansichten.
Bei Ihrer Option 1 habe ich einige Schwierigkeiten zu verstehen, warum Sie sich für die Tri-Link-Tabelle entschieden haben.
quelle
Beachten Sie zunächst, dass die ideale Lösung in gewissem Maße davon abhängt, welches RDBMS Sie verwenden. Ich werde dann sowohl die Standard- als auch die PostgreSQL-spezifische Antwort geben.
Normalisierte Standardantwort
Die Standardantwort besteht darin, zwei Verknüpfungstabellen zu haben.
Angenommen, wir haben unsere Tabellen:
Dieser Ansatz folgt allen Standardregeln für die Normalisierung und verstößt nicht gegen die traditionellen Prinzipien der Datenbanknormalisierung. Es sollte auf jedem RDBMS funktionieren.
PostgreSQL-spezifische Antwort, N1NF-Design
Zunächst ein Wort darüber, warum PostgreSQL anders ist. PostgreSQL unterstützt eine Reihe sehr nützlicher Methoden zur Verwendung von Indizes über Arrays, insbesondere unter Verwendung sogenannter GIN-Indizes. Diese können die Leistung erheblich verbessern, wenn sie hier richtig eingesetzt werden. Da PostgreSQL auf diese Weise in Datentypen "greifen" kann, ist die Grundannahme von Atomizität und Normalisierung etwas problematisch, um sie hier starr anzuwenden. Aus diesem Grund würde ich empfehlen, die Atomizitätsregel der ersten Normalform zu brechen und sich für eine bessere Leistung auf GIN-Indizes zu verlassen.
Ein zweiter Hinweis hier ist, dass dies zwar eine bessere Leistung bietet, jedoch einige Kopfschmerzen verursacht, da Sie einige manuelle Arbeiten ausführen müssen, damit die referenzielle Integrität richtig funktioniert. Der Kompromiss hier ist also die Leistung für manuelle Arbeit.
Jetzt müssen wir Trigger hinzufügen, um sicherzustellen, dass die Schlüsselwörter ordnungsgemäß verwaltet werden.
Zweitens müssen wir entscheiden, was zu tun ist, wenn ein Schlüsselwort entfernt wird. Derzeit wird ein aus der Schlüsselworttabelle entferntes Schlüsselwort nicht in die Schlüsselwortfelder kaskadiert. Vielleicht ist das wünschenswert und vielleicht auch nicht. Am einfachsten ist es, das Löschen immer einzuschränken und zu erwarten, dass Sie diesen Fall manuell behandeln, wenn er auftritt (verwenden Sie hier aus Sicherheitsgründen einen Auslöser). Eine andere Möglichkeit besteht darin, jeden Schlüsselwortwert, in dem das Schlüsselwort vorhanden ist, neu zu schreiben, um ihn zu entfernen. Auch hier wäre ein Auslöser der Weg, dies zu tun.
Der große Vorteil dieser Lösung besteht darin, dass Sie für sehr schnelle Suchvorgänge nach Schlüsselwörtern indizieren und alle Tags ohne Join abrufen können. Der Nachteil ist, dass das Entfernen eines Keywords schmerzhaft ist und selbst an einem guten Tag keine gute Leistung erbringt. Dies kann akzeptabel sein, da es sich um ein seltenes Ereignis handelt, das einem Hintergrundprozess unterzogen werden könnte, aber es ist ein Kompromiss, der es wert ist, verstanden zu werden.
Kritisieren Sie Ihre erste Lösung
Das eigentliche Problem bei Ihrer ersten Lösung ist, dass Sie keinen möglichen Schlüssel für ObjectKeywords haben. Folglich haben Sie ein Problem, bei dem Sie nicht garantieren können, dass jedes Schlüsselwort nur einmal auf jedes Objekt angewendet wird.
Ihre zweite Lösung ist etwas besser. Wenn Ihnen die anderen angebotenen Lösungen nicht gefallen, würde ich vorschlagen, sie zu verwenden. Ich würde jedoch vorschlagen, keyword_id loszuwerden und sich einfach dem Keyword-Text anzuschließen. Dadurch entfällt eine Verknüpfung ohne Denormalisierung.
quelle
Ich würde zwei getrennte Strukturen vorschlagen:
Auf diese Weise haben Sie nicht alle möglichen Entitäts-IDs in derselben Tabelle (was nicht sehr skalierbar ist und verwirrend sein kann), und Sie haben keine Tabelle mit einer generischen "Objekt-ID", die Sie an anderer Stelle eindeutig unterscheiden müssen Verwenden der
base_object
Tabelle, die funktionieren wird, aber ich denke, das Design wird zu kompliziert.quelle
BaseObjects
Tabelle beim ersten Durchlesen verpasst und dachte, ich würde eine Beschreibung für eine Tabelle sehen,object_id
die auf eine ID in einer beliebigen Tabelle verweisen kann .Nach meiner Erfahrung können Sie dies tun.
Für die Beziehung zwischen Schlüsselwörtern, Berichten und Empfehlungen haben Sie zwei Möglichkeiten: Option A:
Dies ermöglicht eine direkte Beziehung von Berichten zu Empfehlungen, zu Schlüsselwörtern und schließlich zu Schlüsselwörtern. Option B:
Die Option A ist einfacher anzuwenden und zu verwalten, da sie über die Einschränkungen der Datenbank verfügt, um die Datenintegrität zu gewährleisten, und das Einfügen ungültiger Daten nicht zulässt.
Die Option B erfordert zwar etwas mehr Arbeit, da Sie die Identifikation der Beziehung codieren müssen. Ist auf lange Sicht flexibler, wenn Sie zu einem späteren Zeitpunkt zufällig Schlüsselwörter zu einem anderen Element als dem Bericht oder der Empfehlung hinzufügen müssen, müssen Sie nur die Identifikation hinzufügen und die Tabelle direkt verwenden.
quelle