喜欢的帖子设计细节

时间:2019-12-27 20:44:48

标签: mysql sql performance database-design

因此,通过研究我发现,设计喜欢的帖子的最佳方法是拥有一个类似以下的数据库。假设像Reddit一样,帖子可以被投票,被投票或完全不投票。

该数据库将具有三列,[用户名,帖子,喜欢的]。

喜欢是某种布尔值,1表示喜欢,0表示不喜欢。

然后要查找类似金额的帖子,例如,我会做SELECT COUNT(*) FROM likes WHERE post=12341 AND liked=1,然后对liked=0做同样的事情(不喜欢),然后在附加服务器端进行辩论,并提出争议百分比。

因此,我首先要担心的是,找出用户是否喜欢帖子的合适方法是什么?我会尝试选择liked布尔值,还是检索或捕获错误。还是我先检查记录是否存在,然后再进行选择以找出该值?如果我想检查用户是否一次喜欢多个帖子怎么办?

第二,该表不需要主键吗?因为没有行将具有相同的帖子和用户名,所以我应该使用复合主键吗?

4 个答案:

答案 0 :(得分:0)

给出建议的3列表格和建议的选择,请确保具有

PRIMARY KEY(username, post)   -- helps with "did user like a post"
INDEX(post_id, liked)  -- for that COUNT

在检查用户是否喜欢帖子时,请执行LEFT JOIN,以便获得以下三项之一:1 =喜欢,0 =不喜欢,或者NULL =不投票。或者,您可以使用EXISTS( SELECT .. )

表需要PK。

答案 1 :(得分:0)

我同意里克·詹姆斯(Rick James)的观点,likes表应该通过({usernamepost)对来唯一索引。
另外,我建议您保留一点冗余,并将like_counter保留在posts表中。这将使您大大减少常规查询的负担。
在成功添加完喜欢/不喜欢记录后,立即增加或减少计数器。

总而言之,

  • 获得喜欢的帖子:简单选择帖子
    无需添加联接和聚合子查询。
  • 喜欢/不喜欢:(1)成功后插入喜欢(2)更新posts.like_counter。
    唯一索引可防止重复。
  • 了解用户是否已喜欢该帖子:按用户名+帖子对从喜欢中进行选择。
    索引有助于快速完成

答案 2 :(得分:0)

我最初的想法是因为问题在于布尔类型不够丰富,无法表达对帖子的可能反应。因此,您需要一个枚举,其状态可能为LikedDisliked,而不是布尔值,并且第三个状态和默认状态为Un-reacted

但是现在看来,您也可以取消布尔值,因为您不需要记录Un-reacted状态。缺乏反应意味着您不会在表中添加条目。


找出用户是否喜欢帖子的合适方法是什么?

SELECT Liked
FROM Likes
WHERE Likes.PostId == 1234
    AND Likes.UserName == "UniqueUserName";

如果用户未与该帖子互动,将不会有任何结果。否则,如果喜欢,则1,如果不喜欢,则0


如果我要检查用户是否一次喜欢多个帖子怎么办?

为此,您还需要存储一个时间戳。然后,您可以使用该时间戳记,看看它是否在短时间内有多个喜欢的帖子。

您可以采用k均值聚类来确定是否有任何“喜欢”集群。完整的说明太大了,无法在此处添加。


此表是否不需要主键?

当然可以。但是Like是弱实体,具体取决于Post。因此,它将需要Post的PK,即字段post(我认为)。结合username我们将拥有PK,因为(postusername)对于用户的反应而言是唯一的。

答案 3 :(得分:0)

为了提高性能,您将需要更改数据库计划:

用户点赞帖子表

字段:

  • Liked应该是布尔值,您是对的。您可以在代码中将其转换为-1 / + 1。您将把数字总计缓存在其他位置。
  • Username应该是UserID。您只需要此表中的数值来提高速度。
  • 出于相同的原因,
  • Post应该为PostID

您还需要数字主键,因为它们更易于搜索和执行子选择。

并在(UsernamePost)上创建唯一索引,因为该表主要是为提高速度而建立的索引。

那么用户对帖子投票了吗?

select id 
from user_likes_post 
where userID = 123 and postID = 456;

用户喜欢帖子吗?

select id 
from user_likes_post 
where userID = 123 and postID = 456 and liked = true;

您不必担心错误,您可以获取结果,也可以不获取结果,因此您最好直接获得所需的值:

select liked from user_liked_post where userID=123 and postID=456

获取他们喜欢的所有帖子:

select postID
from user_likes_post
where userID = 123 and liked = true;

发布分数表

  • PostID
  • TotalLikes
  • TotalDislikes
  • Score

通过对第一个表进行计算,第二个表将每 n 分钟转储并刷新。第二张表是您缓存的总得分,您将为访问该帖子的所有用户实际加载该总得分。调整此重复转储和填充计划的频率,但是您认为合适。对于业余爱好或学生项目,每30秒或2分钟进行一次;较大的站点,每10或15分钟。对于更大的站点,例如reddit,您希望使架构更复杂,以使站点中较忙的部分可以更快地刷新。

// this is not exact code, just an outline

totalLikes = 
 select count(*) 
  from user_likes_post 
  where postID=123 and liked=true
totalDislikes = 
 select count(*) 
  from user_likes_post 
  where postID=123 and liked=false
totalVotes = totalLikes + totalDislikes
score = totalLikes / totalVotes;

(您可以通过涉及用户的localStorage-客户端Javascript来模拟更新,该Javascript显示用户投票过的帖子的上下颠簸。)