Me gusta o vota por publicaciones

10

Estoy haciendo un pequeño programa donde los usuarios hacen publicaciones o escriben blogs. En esas publicaciones, a otros usuarios les puede gustar o no la publicación como en Facebook o votar a favor o en contra de la publicación como en stackoverflow. Me gustaría conocer una buena estructura de base de datos que se usa comúnmente y el programa funciona eficientemente con esa estructura. Tengo dos opciones

primero

Enviar:

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

De la manera anterior, ides el postid. En la columna de me gusta, se 1,2,3encuentra la identificación del usuario a quien le gustó o votó la publicación o el blog. 7,55,44,3es la identificación de los usuarios a los que no les gustó o rechazaron la publicación o el blog.

Segundo

Enviar:

id    head  message   datepost
1     ab    anchdg     DATE

Gustos:

id    postid    userid
1       1         1
2       2         2

No me gusta:

id    postid    userid
1       1         7
2       1         55

De esta manera, tengo que crear dos tablas separadas para Me gusta y No me gusta para obtener Me gusta de la publicación. De esta manera, las tablas, es decir, Likesy Dislikesse llenarán en gran medida. Esto puede hacer que la mesa sea pesada y el procesamiento lento.

Entonces, ¿me gustaría saber cuál es la forma mejor y estándar de lograr esta tarea?

Harshit Shrivastava
fuente
44
¿Asumo que a un usuario no le puede gustar y no me gusta una publicación? Si es así, tendría una tabla para me gusta y no me gusta, con una columna BIT (1 para me gusta, 0 para no me gusta).
dwjv
1
O 1 y -1 para sumas más fáciles
jkavalik
1
@dwjv En el primer ejemplo, al usuario 3, de hecho, le gustó y no le gustó la publicación.
Dan Henderson

Respuestas:

20

El problema que enfrenta se conoce como "formas normales" de bases de datos, especialmente la primera forma normal. https://en.wikipedia.org/wiki/First_normal_form .

Su base de datos con los ID de usuario concatenados (primera versión) no está en la primera forma normal.

Vea https://en.wikipedia.org/wiki/Database_normalization para saber por qué y cómo la normalización generalmente se considera buena.

En su primer ejemplo, la consulta para "al usuario 4 ya no le gusta la publicación" se vuelve complicada. Tendrá que realizar operaciones de cadena, que deberán tener en cuenta los efectos secundarios y los casos de esquina (el usuario es el único usuario "que le gusta", el usuario es el último usuario que le gusta, el usuario está en el medio de la cadena de usuario que le gusta). Esto me parece mal. No lo hagas Utiliza un diseño normalizado.

re: la base de datos se vuelve pesada

Si tiene una publicación que tiene 4 millones de me gusta, en el diseño de la base de datos 1 tendría una fila con una columna de "me gusta" que tiene al menos 4 millones de caracteres de ancho (porque necesitará la coma como caracteres de separación). A continuación, deberá realizar operaciones de cadena en cadenas de cuatro millones de dígitos. Esto es muy poco productivo y lento.

Por otro lado, las bases de datos están diseñadas para manejar millones de filas. Tenemos bases de datos con varios cientos de millones de filas y count (): las operaciones son rápidas. Extremadamente rápido. Entonces no, esto no será un cuello de botella en el rendimiento.

El siguiente problema sería la legibilidad y la mantenibilidad.

Por ejemplo, dime qué hacen estas 2 declaraciones:

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
til_b
fuente
Como mencioné, si hay millones o miles de millones de `` me gusta '' presentes en la mesa, ¿entonces la mesa no se volvería pesada? ¿No tomaría mucho tiempo buscar una tabla con millones de registros ya que la tabla se llenará muy rápido?
Harshit Shrivastava
66
@HarshitShrivastava mysql puede manejar tablas simples de billones de filas, pero imagina esos billones (dis) likes como cadenas en tu tabla de usuarios, que podrían ser aún más grandes y difíciles de trabajar.
jkavalik
3
Una cosa que @til_b no menciona directamente (pero generalmente se implica mediante el uso de formas normales) es que el segundo diseño, implementado adecuadamente, permitirá que el motor de la base de datos subyacente mantenga una integridad referencial que no se puede hacer con el primer patrón de diseño. Eso significa esencialmente que, si el Usuario 4 se elimina, la base de datos borrará los datos vinculados porque sabe qué registros dependen del registro del Usuario 4. El primer diseño es incapaz de esto porque la base de datos no sabe intuitivamente cómo administrar la relación en la cadena.
David Antaramian
9

La segunda forma es mucho mejor porque puede agregar o quitar fácilmente un Me gusta / No me gusta.

Pero debe modificar su segunda solución utilizando una tabla para me gusta o no.
Las columnas de la tabla like / dislike deben ser id, postid, userid y otra para el valor de like o dislike, por ejemplo, 1 para dislike y -1 para like.

Establezca post_id y user_id como clave principal compuesta y funciona bien.

El tamaño de la mesa crecerá con el tiempo. pero solo tienes dos columnas reales. El id y el valor de like / dislike. El postid y userid solo están vinculados a él y se almacenan en su usuario y tabla de publicación.

Julian S
fuente
3
Deberías haberlo hecho user_id, post_idy valueen la mesa. No hay necesidad de una idcolumna separada .
jkavalik
3
Como sugirió el comentario de @ jkavalik sobre la pregunta, 1 y -1 probablemente serían mejores valores para me gusta y disgusto que 1 y 2, ya que permitiría el cálculo de una puntuación total mediante una simple suma de tabla, en lugar de restar el recuento de filas con "2" del recuento de filas con "1".
Dan Henderson
@DanHenderson: Algo así como Me gusta - No me gusta podría ser bastante más rápido que una suma. (Dicho esto, sin embargo, también funcionaría con 1 y -1.)
cHao
¿Cómo lo harías si hubieras dicho 2 acciones más como el amor y la ira? Me refiero al 1 para
Me
Si no quieres sumnada, puedes establecer amor = 2 e ira = 3
Julian S