Curtidas ou votos nas postagens


10

Estou criando um pequeno programa em que os usuários fazem postagens ou escrevem blogs. Nessas postagens, outros usuários podem gostar ou não da postagem como no facebook ou com voto positivo ou negativo na postagem como no stackoverflow. Eu gostaria de conhecer uma boa estrutura de banco de dados que é comumente usada e o programa funciona eficientemente com essa estrutura. Eu tenho duas opções

Primeiro

Postar:

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

Da maneira acima, idé o postid. Na coluna de curtidas, 1,2,3está o ID do usuário que curtiu ou votou positivamente na postagem ou no blog. 7,55,44,3é o ID dos usuários que não gostaram ou votaram negativamente na postagem ou no blog.

Segundo

Postar:

id    head  message   datepost
1     ab    anchdg     DATE

Curtidas:

id    postid    userid
1       1         1
2       2         2

Não gosta:

id    postid    userid
1       1         7
2       1         55

Dessa forma, eu tenho que criar duas tabelas separadas para curtidas e não curtidas para obter curtidas das postagens. Dessa forma, as tabelas ie Likes& Dislikesserão preenchidas intensamente. Isso pode tornar a tabela pesada e o processamento lento.

Então, eu gostaria de saber qual é a melhor e padrão maneira de realizar essa tarefa?


4
Suponho que um usuário não possa gostar e não gostar de uma postagem? Nesse caso, eu teria uma tabela para curtidas e não curtidas, com uma coluna BIT (1 para curtir, 0 para curtir).
dwjv

11
Ou 1 e -1 para somas mais fáceis
jkavalik

11
@dwjv No primeiro exemplo, o usuário 3 gostou e não gostou da publicação.
Dan Henderson

Respostas:


20

O problema que você enfrenta é conhecido como "Formas normais" de bancos de dados, especialmente a primeira forma normal. https://en.wikipedia.org/wiki/First_normal_form .

Seu banco de dados com os IDs de usuário concatenados (primeira versão) não está na primeira forma normal.

Consulte https://en.wikipedia.org/wiki/Database_normalization para saber por que e como a normalização é geralmente considerada boa.

No seu primeiro exemplo, a consulta para "o usuário 4 não gosta mais da postagem" se torna complicada. Ele terá que executar operações de string, que deverão considerar efeitos colaterais e casos de canto (usuário é o único usuário que gosta), usuário é o último usuário que gosta, usuário está no meio da string de usuário que gosta). Eu acharia isso tão ruim. Não faça isso. Use um design normalizado.

re: banco de dados fica pesado

Se você tiver uma postagem com 4 milhões de curtidas, no design do banco de dados 1, você terá uma linha com uma coluna "curtidas" com pelo menos 4 milhões de caracteres (porque você precisará da vírgula como caracteres separados). Você precisará executar operações de seqüência de caracteres com quatro milhões de dígitos. Isso é muito fraco e lento.

Por outro lado, os bancos de dados são projetados para lidar com milhões de linhas. Temos bancos de dados com várias centenas de milhões de linhas e count () - as operações são rápidas. Extremamente rápido. Portanto, não, isso não será um gargalo de desempenho.

A próxima edição seria legibilidade e manutenção.

Por exemplo, diga-me o que essas duas instruções fazem:

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

Como mencionei, se milhões ou milhões de curtidas estiverem presentes na tabela, a tabela não ficará pesada? Não demoraria muito tempo para pesquisar em uma tabela com dezenas de registros, pois a tabela será preenchida muito rapidamente?
Harshit Shrivastava

6
O @HarshitShrivastava mysql pode lidar com tabelas simples de bilhões de linhas, mas imagine esses bilhões (des) gostos como strings na sua tabela de usuários - que podem ser ainda maiores e difíceis de trabalhar.
Jkavalik

3
Uma coisa que @til_b não menciona diretamente (mas geralmente está implícita no uso de formulários normais) é que o segundo design, implementado adequadamente, permitirá que o mecanismo de banco de dados subjacente mantenha a integridade referencial, o que não pode ser feito com o primeiro padrão de design. Isso significa essencialmente que, se o Usuário 4 for excluído, o banco de dados limpará os dados vinculados porque sabe quais registros dependem do registro do Usuário 4. O primeiro design é incapaz disso, porque o banco de dados não sabe intuitivamente como gerenciar a relação na string.
David Antaramian

9

A segunda maneira é muito melhor, porque você pode adicionar ou remover facilmente um gostar / não gostar.

Mas você deve modificar sua segunda solução usando uma tabela para gostar ou não.
As colunas da tabela de gostar / não gostar devem ser id, postid, userid e outra para o valor de gostar ou não gostar, por exemplo, 1 para não gostar e -1 para gostar.

Defina post_id e user_id como uma chave primária composta e funciona bem.

O tamanho da tabela aumentará com o tempo. mas você tem apenas duas colunas reais. O id e o valor do gostar / não gostar. O postid e o userid são vinculados apenas a ele e armazenados em sua tabela de usuário e postagem.


3
Você deveria ter user_id, post_ide valuena mesa. Não há necessidade de uma idcoluna separada .
Jkavalik

3
Como o comentário de @ jkavalik sobre a questão sugeriu, 1 e -1 provavelmente seriam melhores valores para gostar e não gostar que 1 e 2, pois permitiria o cálculo de uma pontuação total por meio de uma simples soma da tabela, em vez de subtrair a contagem de linhas com "2" da contagem de linhas com "1".
Dan Henderson

@ DanHenderson: Algo como gostar - não gostar pode ser um pouco mais rápido que uma soma. (Dito isto, porém, que também trabalharia com um e -1.)
Chao

votado, como você faria isso se tivesse dito mais duas ações como amor e raiva? i significa a 1 para gostos e -1 para não gosta com mais 2 acções
PirateApp

Se você não quer sumqualquer coisa que você pode definir o amor = 2 e raiva = 3
Julian S
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.