【问题标题】:What would be the best solution performance-wise for this upvote/downvote mechanism? [closed]对于这种upvote/downvote 机制,在性能方面最好的解决方案是什么? [关闭]
【发布时间】:2021-07-16 12:43:20
【问题描述】:

我正在构建一个问答平台,人们可以像这里或 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. 在每个问题的每次迭代中运行一个额外的查询,并检查每个问题的数据记录,如果我作为当前用户已投票/否决它?

【问题讨论】:

  • 性能方面,涉及的数据集可能大小,我怀疑它有什么不同

标签: php mysql laravel eloquent query-optimization


【解决方案1】:

每次有人查看问题时计算选票会导致问题获得更多选票所需的时间越来越长,因为它需要从question_votes 表中扫描更多行。您应该希望它花费相同的时间来查看一个全新的问题,就像一个已被多次投票的问题一样。

因此,您可以使用当前总数存储一列 questions.score

当用户赞成或反对时,在question_votes 表中插入一行投票,因此会有记录。如果您想允许用户更改投票,这是必要的。

但同时用户投票,增加或减少questions.score 值并更新questions 表中的行。

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

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

PostsComments 表包含一个 Score 列,即使个别投票存储在 Votes 表的行中。

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


你的评论:

您必须查询question_votes 表以了解当前用户是否对给定问题进行了投票。好消息是,您需要检查的行数最多为每个问题一个,对吗?因此,如果您为支持此查询的表建立索引,则无需检查许多行。

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

我只展示 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的固定值,则返回非空结果。如果没有匹配的行,则由于外连接,它将为 v 的所有列返回 NULL。

【讨论】:

  • 谢谢你,比尔!很荣幸从您那里得到详细的答复!这对我有很大帮助。我很想听听您对其他问题的看法,以了解当前用户是否赞成或反对某个问题。我应该将其作为子查询包含在同一个查询中,还是在每次迭代时添加另一个查询,同时遍历问题以确定我(作为用户)是否对问题投了赞成票/反对票?
猜你喜欢
  • 1970-01-01
  • 2011-10-09
  • 1970-01-01
  • 1970-01-01
  • 2010-09-05
  • 2018-01-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多