Implementieren von Kommentaren und Likes in der Datenbank

145

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 : Photomit Fotos , Articlesmit Artikeln , Placesmit 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:

  1. in der Photo/Article/PlaceTabelle element ( )
  2. durch Auswahl von count ().

Ich hoffe, dass meine Erklärung des Problems jetzt gründlicher ist.

Kokos
quelle
Haben Sie XML in Betracht gezogen?
CodyBugstein
1
Ich finde selten Fragen wie diese, die zu 100% das sind, was ich im Kopf habe. Ihre Frage ist unglaublich vollständig! Danke @Kokos.
Aderchox

Antworten:

194

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:

Kategorie

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:

ER-Diagramm


Übrigens gibt es ungefähr drei Möglichkeiten, die "ER-Kategorie" zu implementieren:

  • Alle Typen in einer Tabelle.
  • Alle Betontypen in separaten Tabellen.
  • Alle konkreten und abstrakten Typen in separaten Tabellen.

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).

Branko Dimitrijevic
quelle
2
tolle Antwort, danke. Ich hoffe, ich werde es schaffen, es zu implementieren ... und ich frage mich, wie Django ORM damit umgehen wird, um es abzubilden (oder wie ich das selbst machen werde ... aber das ist das andere Problem;)) Aber können Sie das erklären? Ich, weil ich glaube, ich verstehe es nicht richtig - was Sie für mich gezeichnet haben (danke!), ist der dritte Ansatz, den Sie erwähnt haben?
Kokos
2
@Kokos Im Wesentlichen bedeutet der Ansatz (3), dass ENTITY eine Tabelle ist, PHOTO eine Tabelle, ARTIKEL eine Tabelle und PLACE eine Tabelle. Der Ansatz (2) würde bedeuten, dass es keine Tabelle für ENTITY gibt, und der Ansatz (1) würde bedeuten, dass es nur eine Tabelle gibt. Die Existenz all dieser Ansätze (alle mit ihren Stärken und Schwächen) ist die unglückliche Folge der Tatsache, dass ein typisches RDBMS die Tabellenvererbung nicht nativ unterstützt.
Branko Dimitrijevic
1
+1 danke für die tolle Erklärung und Hinweise zu "Kategorien". Ich wollte eine Frage in der Nähe stellen, aber Sie haben sie hier beantwortet.
Andy Holaday
2
@BrankoDimitrijevic Warum können die Entitätstabellen Photo, Article, Place keine eigene PK haben, z. B. PhotoID, ArticleID usw., aber auch eine andere Spalte für die Entity_ID als FK? Ist das unnötig?
Band eins
3
@Orion Das Maximum für BIGINTist 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!
Branko Dimitrijevic
22

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.

Wallyk
quelle
2
Weil ich es selbst implementieren muss. Zumindest für den Moment ... und ich dachte, dass es vielleicht eine gute Gelegenheit ist, eine Datenbank ein wenig zu mögen;) Vielen Dank für Ihren Vorschlag mit gespeicherter Prozedur. Weiß jemand, ob er von Django ORM automatisch zugeordnet wird?
Kokos
6
Ich liebe deinen letzten Satz - Beim zweiten Mal ist es immer besser.
Lewis
2
Beim zweiten Mal ist es immer besser. Yup
Gammer
20

Dies ist eine allgemeine Idee. Bitte achten Sie nicht besonders auf das Styling der Feldnamen, sondern mehr auf die Beziehung und Struktur

Geben Sie hier die Bildbeschreibung ein

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).

SELECT * FROM actions  
WHERE actions.id_Stuff = 5  
AND actions.typeStuff="photo"  
AND actions.typeAction = "like"  
user964260
quelle
Ich denke, Sie mögen vielleicht sogar Kommentare, wenn Sie in einem Kommentar auf einen "Gefällt mir" -Link klicken. Diese Abfrage wird wie ein Kommentar (Aktion) mit der ID 133: SELECT * FROM actions WHERE actions.id=133 AND actions.typeStuff = "comment" AND actions.typeAction = "like"
user964260
1
Ich werde mich definitiv an diese Lösung für weitere Versionen meines Systems erinnern :)
Kokos
Ich habe 2 Stofftabellen stuff1 und stuff2 ... Ich habe dieses Diagramm befolgt, aber es gibt einen SQL-Fehler bei der Verwendung dieses ... stuff1, stuff2 sind zwei unabhängige Tabellen mit ihren unabhängigen Primärschlüsseln, und die Aktionstabelle hat eine Spalte id_stuff, auf die verwiesen wird diese beiden tabels stuff1, stuff2. Zum Beispiel hat stuff1 5 Zeilen, stuff2 hat 10 Zeilen. Wenn ich versuche, eine Zeile in der Aktionstabelle mit id_stuff hinzuzufügen, die kleiner als 5 ist, sagen wir '3', führt sie eine Abfrage aus, da sowohl in stuff1 als auch in stuff1 eine Zeile mit id_stuff '3' vorhanden ist stuff2, aber wenn ich versuche, eine Zeile mit id_stuff größer als 5 hinzuzufügen ... (weiter zum nächsten Kommentar)
vikas devde
1
Wenn man Likes auf diese Weise implementieren möchte, wird es schwieriger, den Benutzer über die neuen Likes zu informieren. Es würde einen anderen Tisch erfordern.
Greg L
4
Wie enthält die id_stuffSpalte eindeutige Werte in jeder der drei Tabellen?
Band eins
0

so weit ich das verstehe. Es sind mehrere Tabellen erforderlich. Es gibt viele zu viele Beziehungen zwischen ihnen.

  • Tabelle, in der die Benutzerdaten wie Name, Nachname, Geburtsdatum mit einem Identitätsfeld gespeichert sind.
  • Tabelle, in der Datentypen gespeichert sind. Diese Typen können Fotos, Freigaben, Links sein. Jeder Typ muss eine eindeutige Tabelle haben. Daher besteht eine Beziehung zwischen ihren einzelnen Tabellen und dieser Tabelle.
  • Jeder andere Datentyp hat seine Tabelle. Zum Beispiel Statusaktualisierungen, Fotos, Links.
  • Die letzte Tabelle enthält viele bis viele Beziehungen, in denen eine ID, eine Benutzer-ID, ein Datentyp und eine Daten-ID gespeichert sind.
erencan
quelle
wenn Sie Ihr Datenbankdiagramm veröffentlichen. Ich kann die Beziehung zeichnen.
Erencan
0

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:

  1. Kommentar hinzufügen: Sie wählen entweder eine bestimmte Anzahl von vielen / vielen aus oder fügen sie in eine gemeinsame Tabelle mit einer bekannten spezifischen Kennung für das ein, was Ihnen gefällt. Ich denke, dass der Client-Code in Ihrem zweiten Fall etwas einfacher ist.
  2. Kommentare für Element suchen: Hier scheint es etwas einfacher zu sein, eine gemeinsame Tabelle zu verwenden - wir haben nur eine einzige Abfrage, die nach Entitätstyp parametrisiert ist
  3. Finden Sie Kommentare einer Person zu einer Sache: in beiden Fällen eine einfache Abfrage
  4. Finden Sie alle Kommentare einer Person zu allen Dingen: Dies scheint so oder so wenig knorrig.

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.

djna
quelle
0

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 ...

niemand
quelle
-1

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.

Oroboros102
quelle
Mehr Tabellen bedeuten, dass es weniger wartbar ist. Einzelne Tabellen können von den meisten d / bs geteilt werden.
Wallyk