Domanda

Questa è una domanda circa compromessi.

Immaginate un social network. Ogni utente ha un messaggio di stato, che può cambiare in qualsiasi momento. Ogni volta che non cambia è, tutti i suoi amici vengono notificati attraverso una parete (come in Facebook).

Per fare questo lavoro. Abbiamo 3 tavoli utenti (id, nome), FriendLists (UserID, friendUserId), Comunicazioni (?).

Ora supponiamo ogni utente ha circa 50 amici nella sua lista di amici. Mi trovo di fronte al dilemma -. Come implementare tabella Notifiche


prima opzione

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

Invia notifiche:

-- 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 questo caso, per ogni cambiamento di stato che creiamo 50 record (supponendo 50 amici). Questo non va bene. Tuttavia, il buon punto è che per recuperare le notifiche per un utente specifico, è veramente veloce, dal momento che abbiamo un indice cluster sulla toUserId.

2 ° opzione

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)

Invia notifiche:

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

Qui inseriamo solo un singolo record per aggiornamento di stato. Questo è buono. Il punto negativo è che il recupero delle notifiche sta per essere più lento, dal momento che i record non sono raggruppati per toUserId.


notifiche Come è lo stesso per entrambi i metodi:

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

Allora, qual è la vostra opinione su questo?

È stato utile?

Soluzione

In primo luogo, si legge sta andando sempre essere schiacciante in confronto con operazioni di scrittura, perché ogni 'muro' sarà visto molte più volte di quanto non sarà aggiornato. Quindi è meglio fare legge maledettamente veloce.

In secondo luogo, uno dei problema inerente in questo tipo di grandi siti di social networking è la distribuzione dei dati (sharding, partizionamento, nessun singolo database sarà mai in grado di memorizzare tutti i conti, tutti gli amici, tutte le notifiche) il che significa che quando una nuova notifica è messo su un muro, gli amici devono essere notificate su altri server. Ciò implica aggiornamenti sono asincrone e la messaggistica basata comunque.

Quindi, avrei sicuramente andare con una struttura ottimizzata per la lettura.

Mi consiglia di andare sopra le presentazioni pubbliche fatte da varie persone coinvolte nella architettura dei siti come Facebook e MySpace, come questo di Christa Stelzmuller uno . Essi spiegano un sacco di pensiero e il ragionamento che va in loro design.

Altri suggerimenti

Gli aggiornamenti sono molto lento rispetto a SELECT ... un paio di ordini di grandezza. In più, come il vostro sito scale sarete caching tutti i recuperi in memoria, quindi la velocità di seleziona sarà banale.

In questa situazione, sembra una cattiva idea di creare un indice cluster (touser, identità), perché un indice cluster dovrebbe davvero essere inseriti in ordine crescente. Naturalmente SQL si prenderà cura di mantenere la tabella ordinata, ma questo ha un costo ad alte prestazioni (che è il punto della sua domanda.) Ma in generale, gli inserti che sono noti prima del tempo per essere in nessun ordine particolare, non sono raccomandati per indici cluster. Ecco un ottimo tre parte articolo circa le raccomandazioni indice cluster.

Detto questo, mi piacerebbe restare con la colonna di identità come il vostro indice cluster e creare un indice non cluster su toUserId e forse una colonna datetime. Includendo una colonna datetime, è possibile interrogare in modo più efficiente per i recenti dati.

Per quanto riguarda gli aggiornamenti lenti, gli aggiornamenti di stato su siti di social networking sono una situazione ideale per le code di messaggi. In questo modo è possibile ottimizzare il database come necessario per rendere legge velocemente e se ha un impatto sulle prestazioni in scrittura, l'utente non dovrà soffrire. Dal loro punto di vista l'aggiornamento è istantanea, anche se potrebbe richiedere alcuni minuti a "bastone".

Per database di grandi dimensioni che verrà rinviare ai guru SQL che possono parlare di partizionamento strategie (piccoli tavoli più gestibili per i dati più recenti, più grandi / tavoli pesantemente indicizzati per i dati meno recenti) e soluzioni di replica.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top