对于此 upvote/downvote 机制,性能方面的最佳解决方案是什么?

What would be the best solution performance-wise for this upvote/downvote mechanism?

我正在构建一个问答平台,人们可以在这里 upvote/downvote 点赞或点赞 Reddit。

$questions =
 Question::select([
 'questions.*',
 'users.name AS username'
    ])
    ->leftJoin('questions_votes', 'questions_votes.question_id', '=', 'questions.id')
    ->leftJoin('users', 'users.id', '=', 'questions.user_id')
    ->groupBy('questions.id')
    ->get();

通过这个查询,我得到了每个问题的总数、创建者的用户名和问题数据本身。

所有投票都存储在 questions_votes(列:id, user_id, upvote)中,其中 upvote 可以是 1 表示赞成票或 -1 表示反对票。

获得用户投票数据性能的最佳方法是什么?我应该...

  1. 在我的 $questions 查询中添加一个额外的子查询来检查该用户的每个问题的 upvote 列?该子查询在普通 MySQL?
  2. 中看起来如何
  3. 运行 对每个问题的每次迭代进行额外查询,并检查每个问题的数据记录,如果我作为当前用户有 upvoted/downvoted 它?

每次有人查看问题时都会计算投票数,因为问题收到的投票数会越来越多,因为它需要扫描 question_votes table 中的更多行。您应该希望它花费相同的时间来查看一个全新的问题,因为它已被投票很多。

因此您可以将当前总数存储在 questions.score 列中。

当用户投赞成票或反对票时,在 question_votes table 中插入一行投票,这样就有了记录。如果您想允许用户更改他们的投票,这是必要的。

但同时用户也投票,增加或减少 questions.score 值并更新 questions table.

中的行

理想情况下,如果完美地完成此操作,questions.score 将是赞成票和反对票的总和。但有可能由于代码错误,它不会一直都是完美的。事实上,假设它会变得稍微不准确。因此,您可能需要一个“双重检查”后台任务来定期重新计算分数总和并修复分数。

这就是 Stack Overflow 所做的,如下所示:https://meta.stackexchange.com/questions/2677/database-schema-documentation-for-the-public-data-dump-and-sede

PostsComments table 包含一个 Score 列,即使个人投票存储在 Votes [=60] 的行中=].

性能的优势在于,当某些用户只是查看问题时,您不需要从 question_scores table 中读取任何行。查看问题的次数可能比投票的次数多很多,因此您可以通过存储投票总和来避免一遍又一遍地重新计算完全相同的总和值。


回复您的评论:

您必须查询 question_votes table 才能查明当前用户是否对给定问题进行了投票。好消息是每个问题最多需要检查的行数,对吗?因此,如果您有 table 索引来支持此查询,则无需检查许多行。

无论您是在连接查询还是在第二个查询中执行此操作,它都非常轻量级,因为它只会执行单行查找。

我只显示 SQL,因为我不经常使用 Laravel。

SELECT q.*, (v.user_id IS NOT NULL) AS i_voted_on_it
FROM questions q
LEFT OUTER JOIN question_votes v 
 ON v.question_id = q.id AND v.user_id = ?

如果您在 question_votes(question_id, user_id) 上有一个索引,那么进行查找会更有效率。

如果有符合条件的行,包括user_id的固定值,那么会return一个非空结果。如果没有匹配的行,那么由于外部连接,v 的所有列都将 return NULL。