Ich bin auf der Suche nach der besten Möglichkeit, eine Reihe von "Posts" sowie Kommentare zu diesen Posts in SQL zu speichern. Stellen Sie sich ein Design vor, das einem "Wall" auf Facebook ähnlich ist, wo Benutzer Posts auf ihre Pinnwand schreiben können und andere Benutzer diese Posts kommentieren können. Ich muss in der Lage sein, alle Pinnwand Beiträge sowie die Kommentare anzuzeigen.Was ist der beste Weg, um eine Thread-Nachrichtenliste/Struktur in SQL zu speichern?
Als ich anfing erste, kam ich mit einem Tisch wie:
CREATE Table wallposts
(
id uuid NOT NULL,
posted timestamp NOT NULL,
userid uuid NOT NULL,
posterid uuid NOT NULL,
parentid uuid NOT NULL,
comment text NOT NULL
)
ID ist einzigartig, parentid wird auf Original-Beiträge und weisen auf eine ID null sein, wenn die Zeile einen Kommentar über ein ist vorhandener Beitrag Einfach und super schnell um neue Daten einzufügen. Um jedoch eine Auswahl tun, das würde mich zurück:
POST 1
COMMENT 1
COMMENT 2
POST 2
COMMENT 1
COMMENT 2
Unabhängig davon, welcher Reihenfolge die Reihen gab es in der Datenbank als äußerst schwierig erwiesen. Ich kann natürlich nicht einfach nach Datum sortieren, da jemand Post 1 nach Post 2 kommentieren könnte. Wenn ich LINKE VERBINDUNGEN mache, um den übergeordneten Post in allen Zeilen zu erhalten und dann nach diesem Datum zu sortieren, werden alle ursprünglichen Posts zusammen gruppiert, da sie den Wert null haben.
Dann habe ich diese Idee:
CREATE TABLE wallposts
(
id uuid NOT NULL,
threadposted timestamp,
posted timestamp,
...
comment text
)
Auf einem Original-Beitrag, threadposted und geschrieben würde das gleiche sein. Bei einem Kommentar wäre der Zeitstempel der Zeitpunkt, zu dem der ursprüngliche Beitrag gepostet wurde, und der Zeitpunkt, zu dem der Kommentar zu diesem Thread gepostet wurde. Jetzt kann ich nur tun:
select * from wallposts order by threadposted, posted;
Das funktioniert gut, aber eine Sache ärgert mich. Wenn zwei Personen gleichzeitig einen Post erstellen, werden Kommentare zu den beiden Posts zusammengefügt, da sie denselben Timestamp haben. Ich könnte "Ticks" statt einer Datetime verwenden, aber die Genauigkeit beträgt immer noch 1/1000 Sekunde. Ich könnte auch eine eindeutige Beschränkung für Threatposted und Posted einrichten, die Einfügungen ein wenig teurer macht, aber wenn ich mehrere Datenbankserver in einer Farm hatte, ist die Chance einer Kollision immer noch da. Fast hätte ich das trotzdem gemacht, da die Chancen dafür extrem gering sind, aber ich wollte sehen, ob ich meinen Kuchen essen kann und es trotzdem habe. Meistens für meine eigene Bildungswissheit.
Die dritte Lösung wäre, diese Daten in Form eines Graphen zu speichern. Jeder Knoten würde einen Zeiger v-links und v-rechts haben. Ich könnte nach "links" bestellen, was den Baum in der Reihenfolge durchqueren würde, die ich brauche. Jedes Mal, wenn jemand einen Kommentar einfügt, muss ich den gesamten Baum neu ausbalancieren. Dies würde eine Menge Zeilensperren und alle möglichen Probleme verursachen, wenn die Site sehr beschäftigt wäre. Außerdem ist es extrem und verursacht auch Replikationsprobleme. Also habe ich diese Idee schnell geworfen.
Ich dachte auch darüber nach, nur die ursprünglichen Posts zu speichern und dann die Kommentare in einer binären Form zu serialisieren, denn wer kümmert sich um einzelne Kommentare. Dies wäre sehr schnell, wenn jedoch ein Benutzer seinen Kommentar löschen oder einen neuen Kommentar an das Ende anhängen möchte, muss ich diese Daten deserialisieren, die Struktur ändern, sie dann serialisieren und die Zeile aktualisieren. Wenn mehrere Personen gleichzeitig den gleichen Beitrag kommentieren, kann es zu zufälligen Problemen kommen.
Also hier ist was ich schließlich getan habe. Ich erkundige mich nach allen Posts geordnet nach dem eingegebenen Datum. In der Middleware-Schicht durchlaufe ich das Recordset und erstelle einen "Stapel" von Original-Posts, jeder Knoten auf dem Stack zeigt auf eine verknüpfte Liste von Kommentaren. Wenn ich auf einen originalen Post stoße, schiebe ich einen neuen Knoten auf den Stapel und wenn ich auf einen Kommentar stoße, füge ich einen Knoten zur verknüpften Liste hinzu. Ich organisiere das im Speicher, damit ich das Recordset einmal durchqueren kann und O (n) habe. Nachdem ich die In-Memory-Darstellung der Wand erstellt habe, durchquere ich diese Datenstruktur erneut und schreibe HTML aus.Das funktioniert super und hat super schnelle Inserts und super schnelle Selects und keine seltsamen Zeilensperrprobleme; Allerdings ist es auf meiner Präsentationsebene etwas schwerer und erfordert, dass ich eine In-Memory-Repräsentation der Wand des Benutzers erstelle, um Dinge herum zu bewegen, so dass es in der richtigen Reihenfolge ist. Trotzdem glaube ich, dass dies der beste Ansatz ist, den ich bisher gefunden habe.
Ich dachte, ich würde mit anderen SQL-Experten überprüfen, ob es eine bessere Möglichkeit gibt, dies mit einigen seltsamen JOINS oder UNIONS oder etwas zu tun, das immer noch mit Millionen von Benutzern performant wäre.
Es tut mir leid für die nicht klar zu sein. Ich brauche die Zeilen in der Reihenfolge, in der sie in der Benutzeroberfläche angezeigt werden sollten: Post eins, Kommentare zu Post eins, Post zwei, Kommentare zu Post 2 usw. Wenn ich sie neu anordnen muss, um HTML zu rendern, könnte ich auch einfach nur erstellen eine Karte im Speicher. –