Mi piace o voti per i post


10

Sto realizzando un piccolo programma in cui gli utenti pubblicano post o scrivono blog. Su questi post, altri utenti possono apprezzare o non apprezzare il post come in Facebook o aumentare il voto o ridimensionare il post come in StackOverflow. Mi piacerebbe conoscere una buona struttura di database che è comunemente usata e il programma funziona in modo efficiente con quella struttura. Ho due opzioni

Primo

Inviare:

id   head   message   datepost   likes   dislikes
1     ab    anchdg     DATE      1,2,3   7,55,44,3

Nel modo sopra, idè il postide. Nella colonna 1,2,3Mi piace è l'ID dell'utente a cui è piaciuta o aggiunta la votazione al post o al blog. 7,55,44,3è l'id degli utenti che non hanno gradito o votato per il downgrade del post o del blog.

Secondo

Inviare:

id    head  message   datepost
1     ab    anchdg     DATE

Piace:

id    postid    userid
1       1         1
2       2         2

Non mi piace:

id    postid    userid
1       1         7
2       1         55

In questo modo, devo creare due tabelle separate per Mi piace e Non mi piace per ottenere Mi piace dei post. In questo modo, le tabelle cioè Likese Dislikesverranno riempite pesantemente. Ciò potrebbe rendere la tabella pesante e l'elaborazione lenta.

Quindi, vorrei sapere qual è il modo migliore e standard per raggiungere questo obiettivo?


4
Suppongo che a un utente non piaccia e non piaccia un post? In tal caso, avrei una tabella per Mi piace e Non mi piace, con una colonna BIT (1 per Mi piace, 0 per Non mi piace).
dwjv,

1
O 1 e -1 per somme più facili
jkavalik,

1
@dwjv Nel primo esempio, l'utente 3 è, infatti, sia voluto e antipatico il palo.
Dan Henderson,

Risposte:


20

Il problema che affronti è noto come "Forme normali" dei database, in particolare la prima forma normale. https://en.wikipedia.org/wiki/First_normal_form .

Il tuo database con gli ID utente concatenati (prima versione) non è nella prima forma normale.

Vedi https://en.wikipedia.org/wiki/Database_normalization per perché e come la normalizzazione è generalmente considerata buona.

Nel tuo primo esempio, la query per "l'utente 4 non piace più il post" diventa complicata. Dovrà eseguire operazioni sulle stringhe, che dovranno considerare gli effetti collaterali e i casi angolari (l'utente è l'unico utente "di gradimento", l'utente è l'ultimo utente di gradimento, l'utente si trova nel mezzo della stringa di utenti di gradimento). Lo troverei male. Non farlo Usa un design normalizzato.

re: il database diventa pesante

Se hai un post che ha 4 milioni di Mi piace, nella progettazione del database 1 avresti una riga con una colonna "Mi piace" che è larga almeno 4 milioni di caratteri (perché avrai bisogno della virgola come caratteri separati). Dovrai quindi eseguire operazioni sulle stringhe su stringhe larghe da quattro milioni di cifre. Questo è molto poco performante e lento.

D'altra parte, i database sono progettati per gestire milioni di righe. Abbiamo database con diverse centinaia di milioni di righe e count () - le operazioni sono veloci. Estremamente veloce. Quindi no, questo non sarà un collo di bottiglia delle prestazioni.

Il prossimo numero sarebbe leggibilità e manutenibilità.

Ad esempio, dimmi cosa fanno queste 2 affermazioni:

select count(*)
from posts
inner join likes on posts.postid = likes.postid
where postid = 7

select len(likes) - len(replace(likes, ',', ''))
from posts
where postid = 7

Come ho già detto, se crores o miliardi di like presenti nel tavolo, allora il tavolo non diventerebbe pesante? Non ci vorrebbe molto tempo per cercare un tavolo con decine di record dal momento che il tavolo si riempirà molto velocemente?
Harshit Shrivastava,

6
@HarshitShrivastava mysql può gestire semplici tabelle da miliardi di righe, ma immagina quei miliardi (dis) come stringhe nella tabella degli utenti - che potrebbero essere ancora più grandi e difficili da lavorare.
jkavalik,

3
Una cosa che @til_b non menziona direttamente (ma è generalmente implicita nell'uso di moduli normali) è che il secondo progetto, correttamente implementato, consentirà al motore di database sottostante di mantenere l'integrità referenziale che non può essere fatta con il primo modello di progetto. Ciò significa essenzialmente che, se l'utente 4 viene eliminato, il database cancella i dati collegati perché sa quali record dipendono dal record dell'utente 4. Il primo progetto non è in grado di farlo perché il database non sa intuitivamente come gestire la relazione nella stringa.
David Antaramian,

9

Il secondo modo è molto meglio perché puoi facilmente aggiungere o rimuovere un like / antipatia.

Ma dovresti modificare la tua seconda soluzione usando una tabella per like o antipatia.
Le colonne della tabella like / antipatia dovrebbero essere id, postid, userid e un'altra per il valore di like o antipatia, ad esempio 1 per antipatia e -1 per like.

Imposta post_id e user_id come chiave primaria composita e funziona benissimo.

Le dimensioni della tabella cresceranno nel tempo. ma ci sono solo due colonne reali. L'id e il valore del like / dislike. Postid e userid sono solo collegati ad esso e memorizzati nella tabella utente e posta dell'utente.


3
Dovresti avere user_id, post_ide valuenella tabella. Non è necessaria una idcolonna separata .
jkavalik,

3
Come suggerito dal commento di @ jkavalik sulla domanda, 1 e -1 sarebbero probabilmente valori migliori per like e antipatia di 1 e 2, poiché consentirebbe il calcolo di un punteggio totale mediante una semplice somma di tabella, piuttosto che sottrarre il conteggio di righe con "2" dal conteggio delle righe con "1".
Dan Henderson,

@DanHenderson: Qualcosa di simile ai mi piace: le antipatie potrebbero essere un po 'più veloci di una somma. (Detto questo, però, funzionerebbe anche con 1 e -1.)
cHao,

votato, come faresti se avessi detto altre 2 azioni come l'amore e la rabbia? intendo 1 per
Mi

Se non vuoi fare sumnulla puoi impostare amore = 2 e rabbia = 3
Julian S
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.