Frage

Dies ist eine Frage zu Kompromissen.

Stellen Sie sich vor, ein soziales Netzwerk. Jeder Benutzer hat eine Statusmeldung, dass er jederzeit ändern kann. Jedes Mal, wenn er das tut Änderung es, alle seine Freunde sind durch eine Wand gemeldet (wie in Facebook).

Um diese Arbeit zu machen. Wir haben 3 Tabellen Benutzer (id, name), FriendLists (userId, friendUserId), Notifications (?).

Nun nehmen wir an, jeder Benutzer hat etwa 50 Freunde in seiner Freundesliste. Ich bin mit dem Dilemma konfrontiert -. Wie Benachrichtigungen Tabelle implementieren


1. Option

CREATE TABLE Notifications
(
toUserId bigint NOT NULL,
[identity] bigint IDENTITY(1,1) NOT NULL,
fromUserId bigint NOT NULL,
data varchar(256) NOT NULL,
CONSTRAINT [PK_Notifications] PRIMARY KEY CLUSTERED (toUserId, [identity])
)

Senden Benachrichtigungen:

-- Get all friends of @fromUserId.
WITH Friends AS
   (SELECT FriendLists.friendUserId
 FROM FriendLists
 WHERE userId = @fromUserId)
-- Send updates to all friends.
SELECT
 friendUserId as toUserId,
 @fromUserId as fromUserId,
 @data as data
INTO Notifications
FROM Friends

In diesem Fall für jede Statusänderung schaffen wir 50 Datensätze (vorausgesetzt, 50 Freunde). Das ist schlecht. Doch der gute Punkt ist, dass die Benachrichtigungen für einen bestimmten Benutzer abzurufen es ist wirklich schnell, da wir einen Clustered-Index auf der toUserId haben.

2. Option

CREATE TABLE Notifications
(
toUserId bigint NOT NULL,
[identity] bigint IDENTITY(1,1) NOT NULL,
fromUserId bigint NOT NULL,
data varchar(256) NOT NULL,
CONSTRAINT [PK_Notifications] PRIMARY KEY CLUSTERED ([identity])
)
CREATE NONCLUSTERED INDEX [IX_toUserId] ON Notifications (toUserId ASC)

Senden Benachrichtigungen:

-- Get all friends of @fromUserId.
WITH Friends AS
   (SELECT FriendLists.friendUserId
 FROM FriendLists
 WHERE userId = @fromUserId)
-- Send updates to all friends.
INSERT INTO Notifications(toUserId, fromUserId, data)
    VALUES(friendUserId, @fromUserId, @data)

Hier haben wir nur einen einzelnen Datensatz pro Status-Update ein. Das ist gut. Die schlechte ist, dass der Abruf der Meldungen langsamer sein wird, da Aufzeichnungen nicht durch toUserId gruppiert.


Erste-Benachrichtigungen ist für beide Methoden:

SELECT TOP(50) fromUserId, [identity], data
FROM Notifications
WHERE toUserId  = @toUserId

Also, was halten Sie von diesem?

War es hilfreich?

Lösung

Zuerst liest werden immer im Vergleich zu überwältigend mit Schreiben, weil jede ‚Mauer‘ noch viele Male zu sehen sein wird, als es aktualisiert. So machen Sie sich besser liest verflixt schnell.

Zweitens, eine des inhärenten Problems in dieser Art von großen Social-Networking-Site ist die Verteilung der Daten (sharding, Partitionierung, keine einzige Datenbank jemals fähig sein, alle Konten zu speichern, alle Freunde, alle Benachrichtigungen), was bedeutet, dass, wenn eine neue Benachrichtigung an eine Wand gestellt wird, haben die Freunde auf andere Server angemeldet werden. Dies bedeutet, Updates sind asynchron und trotzdem basierten Messaging.

Also habe ich auf jeden Fall mit einer Struktur optimiert für das Lesen gehen.

Ich würde empfehlen, die öffentlichen Präsentationen von verschiedenen Menschen in der Architektur von Websites wie Facebook und MySpace beteiligt getan gehen, wie dieses eine der Christa Stelzmüller. Sie erklären, eine Menge von dem Denken und Argumentieren, die in ihrer Gestaltung geht.

Andere Tipps

Updates sind sehr langsam im Vergleich zu SELECTs ... ein paar Größenordnungen. Plus, wie Sie Ihre Website Waage finden Sie alle Ihre Abholungen im Speicher werden das Caching, so dass die Geschwindigkeit von wählt trivial sein wird.

In dieser Situation ist es wie eine schlechte Idee scheint einen Clustered-Index auf (touser, Identität) zu erstellen, da ein Clustered-Index sollte wirklich in aufsteigender Reihenfolge eingefügt werden. Natürlich wird SQL kümmern sortiert die Tabelle zu halten, aber dies kommt zu einem hohen Leistungskosten (was der Punkt Ihrer Frage ist.) Aber im allgemeinen Einsätze, die vor der Zeit bekannt sind, in keiner bestimmten Reihenfolge zu sein, sind nicht zu empfehlen für Clustered-Indizes. Hier ist eine sehr gute drei Teil Artikel über Clustered-Index Empfehlungen.

sagte, dass hat, würde ich mit der Identitätsspalte als gruppierten Index-Stick und einen nicht gruppierten Index auf toUserId und vielleicht eine Datetime-Spalte erstellen. Durch die Einbindung einer Datetime-Spalte können Sie effiziente Abfrage für die jüngsten Daten.

In Bezug auf langsames Updates, Status-Updates auf Social-Networking-Site ist eine perfekte Situation für Nachrichtenwarteschlangen. Auf diese Weise können Sie abstimmen, da die Datenbank zu machen, benötigt liest schnell und wenn es einen Einfluss auf die Schreibleistung hat, wird der Benutzer nicht zu leiden haben. Aus ihrer Sicht war das Update momentane obwohl es ein paar Momente zu „kleben“ nehmen könnte.

Für sehr große Datenbanken werde ich auf die SQL-Gurus verschieben, die über Partitionierungsstrategien (kleinere überschaubare Tabellen für neuere Daten, größer / stark indiziert Tabellen für ältere Daten) und Replikationslösungen sprechen können.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top