Ich bin ein Softwareentwickler. Ich liebe es zu codieren, aber ich hasse Datenbanken ... Derzeit erstelle ich eine Website, auf der ein Benutzer eine Entität als beliebt markieren kann (wie in FB), sie markieren und kommentieren kann .
Ich stecke beim Entwurf von Datenbanktabellen fest, um diese Funktionalität zu handhaben. Die Lösung ist trivial, wenn wir dies nur für eine Art von Dingen tun können (z. B. Fotos). Aber ich muss dies für 5 verschiedene Dinge aktivieren (für den Moment, aber ich gehe auch davon aus, dass diese Anzahl wachsen kann, wenn der gesamte Service wächst).
Ich habe hier einige ähnliche Fragen gefunden, aber keine hat eine zufriedenstellende Antwort. Deshalb stelle ich diese Frage erneut.
Die Frage ist, wie die Datenbank richtig, effizient und elastisch gestaltet werden kann, damit Kommentare für verschiedene Tabellen , Likes für verschiedene Tabellen und Tags für sie gespeichert werden können. Einige Designmuster als Antwort sind am besten;)
Detaillierte Beschreibung : Ich habe eine Tabelle User
mit einigen Benutzerdaten und 3 weitere Tabellen : Photo
mit Fotos , Articles
mit Artikeln , Places
mit Orten . Ich möchte jedem angemeldeten Benutzer Folgendes aktivieren:
Kommentar zu einer dieser 3 Tabellen
Markieren Sie einen von ihnen als gemocht
Kennzeichnen Sie einen von ihnen mit einem Tag
Ich möchte auch die Anzahl der Likes für jedes Element und die Häufigkeit zählen, mit der dieses bestimmte Tag verwendet wurde.
1 st Ansatz :
a) Für Tags , ich werde eine erstellen Tabelle Tag [TagId, tagName, tagCounter]
, dann werde ich schaffen many-to-many - Beziehungen Tabellen für: Photo_has_tags
, Place_has_tag
, Article_has_tag
.
b) Gleiches gilt für Kommentare.
c) Ich werde eine erstellen Tabelle LikedPhotos [idUser, idPhoto]
, LikedArticles[idUser, idArticle]
, LikedPlace [idUser, idPlace]
. Die Anzahl der Likes wird durch Abfragen berechnet (was meiner Meinung nach schlecht ist). Und...
Ich mag dieses Design für den letzten Teil wirklich nicht, es riecht schlecht für mich;)
2 nd Ansatz :
Ich werde eine Tabelle erstellen ElementType [idType, TypeName == some table name]
, die vom Administrator (mir) mit den Namen der Tabellen gefüllt wird , die gemocht , kommentiert oder markiert werden können . Dann werde ich Tabellen erstellen :
a) LikedElement [idLike, idUser, idElementType, idLikedElement]
und dasselbe für Kommentare und Tags mit jeweils den richtigen Spalten. Wenn ich nun ein Foto mögen möchte, füge ich Folgendes ein:
typeId = SELECT id FROM ElementType WHERE TypeName == 'Photo'
INSERT (user id, typeId, photoId)
und für Orte:
typeId = SELECT id FROM ElementType WHERE TypeName == 'Place'
INSERT (user id, typeId, placeId)
und so weiter ... Ich denke, dass der zweite Ansatz besser ist, aber ich habe auch das Gefühl, dass etwas in diesem Design fehlt ...
Schließlich frage ich mich auch, welcher der beste Ort ist, um die Theke zu speichern, wie oft das Element gemocht wurde. Ich kann mir nur zwei Möglichkeiten vorstellen:
- in der
Photo/Article/Place
Tabelle element ( ) - durch Auswahl von count ().
Ich hoffe, dass meine Erklärung des Problems jetzt gründlicher ist.
Antworten:
Die erweiterbarste Lösung besteht darin, nur eine "Basis" -Tabelle (verbunden mit "Likes", Tags und Kommentaren) zu haben und alle anderen Tabellen von dieser zu "erben". Das Hinzufügen einer neuen Art von Entität umfasst das Hinzufügen einer neuen "geerbten" Tabelle - diese wird dann automatisch in die gesamte Like / Tag / Comment-Maschinerie eingebunden.
Der Begriff "Entity-Relationship" lautet hierfür "Kategorie" (siehe ERwin Methods Guide , Abschnitt: "Subtype Relationships"). Das Kategoriesymbol lautet:
Angenommen, ein Benutzer kann mehrere Entitäten mögen, ein Tag kann für mehr als eine Entität verwendet werden, aber ein Kommentar ist entitätsspezifisch. Ihr Modell könnte folgendermaßen aussehen:
Übrigens gibt es ungefähr drei Möglichkeiten, die "ER-Kategorie" zu implementieren:
Sofern Sie keine sehr strengen Leistungsanforderungen haben, ist der dritte Ansatz wahrscheinlich der beste (dh die physischen Tabellen stimmen 1: 1 mit den Entitäten im obigen Diagramm überein).
quelle
BIGINT
ist 9223372036854775807. Angenommen, Sie fügen eine Zeile pro Sekunde ein, werden Ihnen in ~ 300 Milliarden Jahren die verfügbaren Werte ausgehen. Bis dahin können Sie sicher auf 128-Bit-Ganzzahlen portieren!Warum versuchen Sie, eine zu implementieren, da Sie Datenbanken "hassen"? Bitten Sie stattdessen jemanden um Hilfe, der dieses Zeug liebt und atmet.
Ansonsten lernen Sie, Ihre Datenbank zu lieben. Eine gut gestaltete Datenbank vereinfacht die Programmierung, das Engineering der Site und vereinfacht den weiteren Betrieb. Selbst ein erfahrener D / B-Designer hat keine vollständige und perfekte Voraussicht: Einige Schemaänderungen werden später erforderlich sein, wenn Nutzungsmuster auftreten oder sich Anforderungen ändern.
Wenn es sich um ein Ein-Mann-Projekt handelt, programmieren Sie die Datenbankschnittstelle mithilfe gespeicherter Prozeduren in einfache Operationen: add_user, update_user, add_comment, add_like, upload_photo, list_comments usw. Betten Sie das Schema nicht in eine einzige Codezeile ein. Auf diese Weise kann das Datenbankschema geändert werden, ohne dass sich dies auf den Code auswirkt: Nur die gespeicherten Prozeduren sollten über das Schema Bescheid wissen.
Möglicherweise müssen Sie das Schema mehrmals umgestalten. Das ist normal. Mach dir keine Sorgen, dass es beim ersten Mal perfekt wird. Machen Sie es einfach funktional genug, um einen Prototyp eines ersten Entwurfs zu erstellen. Wenn Sie den Luxus der Zeit haben, verwenden Sie sie, löschen Sie das Schema und wiederholen Sie den Vorgang. Beim zweiten Mal ist es immer besser.
quelle
Dies ist eine allgemeine Idee. Bitte achten Sie nicht besonders auf das Styling der Feldnamen, sondern mehr auf die Beziehung und Struktur
Dieser Pseudocode erhält alle Kommentare des Fotos mit der ID 5
SELECT * FROM Actions
WHERE Actions.id_Stuff = 5
AND Actions.typeStuff = "Foto"
AND Actions.typeAction = "Kommentar"
Dieser Pseudocode ruft alle Likes oder Benutzer ab, denen das Foto mit der ID 5 gefallen hat
(Sie können count () verwenden, um nur die Anzahl der Likes zu erhalten).
quelle
SELECT * FROM actions WHERE actions.id=133 AND actions.typeStuff = "comment" AND actions.typeAction = "like"
id_stuff
Spalte eindeutige Werte in jeder der drei Tabellen?so weit ich das verstehe. Es sind mehrere Tabellen erforderlich. Es gibt viele zu viele Beziehungen zwischen ihnen.
quelle
Schauen Sie sich die Zugriffsmuster an, die Sie benötigen. Scheint einer von ihnen meine eine oder andere Designentscheidung besonders schwierig oder ineffizient zu machen?
Wenn nicht, bevorzugen Sie diejenige, die weniger Tabellen benötigt
In diesem Fall:
Ich denke, Ihr "diskriminierter" Ansatz, Option 2, führt in einigen Fällen zu einfacheren Abfragen und scheint in den anderen Fällen nicht viel schlimmer zu sein, also würde ich damit weitermachen.
quelle
Entscheiden Sie sich auf jeden Fall für den zweiten Ansatz, bei dem Sie eine Tabelle haben und den Elementtyp für jede Zeile speichern. Dadurch erhalten Sie viel mehr Flexibilität. Grundsätzlich ist es fast immer besser, mit weniger Tabellen zu arbeiten, wenn etwas logisch mit weniger Tabellen erledigt werden kann. Ein Vorteil, der mir im Moment in Bezug auf Ihren speziellen Fall einfällt, ist, dass Sie alle gewünschten Elemente eines bestimmten Benutzers löschen möchten. Bei Ihrem ersten Ansatz müssen Sie eine Abfrage für jeden Elementtyp ausgeben, beim zweiten Ansatz ist dies jedoch möglich Mit nur einer Abfrage oder Überlegung, wann Sie einen neuen Elementtyp hinzufügen möchten. Beim ersten Ansatz wird für jeden neuen Typ eine neue Tabelle erstellt. Beim zweiten Ansatz sollten Sie jedoch nichts tun ...
quelle
Erwägen Sie die Verwendung einer Tabelle pro Entität für Kommentare usw. Mehr Tabellen - besseres Sharding und Skalieren. Es ist kein Problem, viele ähnliche Tabellen für alle mir bekannten Frameworks zu steuern.
Eines Tages müssen Sie die Lesevorgänge aus einer solchen Struktur optimieren. Sie können problemlos Agragating-Tabellen über Basis-Tabellen erstellen und beim Schreiben etwas verlieren.
Ein großer Tisch mit Wörterbuch kann eines Tages unkontrollierbar werden.
quelle