MySQL-计数行VS设置计数器

时间:2014-06-26 02:10:52

标签: mysql sql

我有2个表 posts <id, user_id, text, votes_counter, created> votes <id, post_id, user_id, vote>。表格投票可以是1(upvote)或-1(downvote)。现在,如果我需要在帖子上获取总票数(upvotes - downvotes),我可以通过两种方式完成。

  1. 使用 count(*) votes表中计算该帖子的upvotes和downvotes的数量,然后进行数学计算。
  2. 设置计数器列votes_counter,并在每次用户upvotes或downvotes时递增或递减。然后只需提取votes_counter
  3. 我的问题是哪一个更好,在什么条件下。通过说条件,我的意思是可扩展性,峰值时间等因素。

    据我所知,如果我使用方法1,对于包含数百万行的表, count(*) 可能是一个繁重的操作。为了避免这种情况,如果我在高峰期使用计数器,则vote_counter列可能会死锁,有太多用户试图更新计数器!

    第三种方法是否比两种方式都更好并且实施起来很简单?

2 个答案:

答案 0 :(得分:4)

这两种方法代表了实施复杂性和速度之间的共同权衡。

  • 第一种方法实现起来非常简单,因为它不需要您进行任何额外的编码。
  • 第二种方法可能要快得多,特别是当您需要计算大表中的一小部分项目时
  • 第一种方法可以通过精心设计的索引来加速。您的RDBMS可以从索引中检索一些记录,并使用它们进行计数,而不是搜索整个表。

第二种方法很快就会变得非常复杂:

  • 您需要考虑用户被删除时计数会发生什么变化
  • 您应该考虑当您的计划外的工具操纵投票表时会发生什么。例如,当当前计数与各个数据库一起存储时,合并两个数据库中的记录可能会复杂得多。

我将从第一种方法开始,看看它的表现如何。然后我会尝试使用索引进行优化。最后,我会考虑使用第二种方法,可能会编写触发器来自动更新计数。

答案 1 :(得分:1)

由于这听起来很像StackExchange,我会在元数据中引用您关于网站上使用的数据库模式的this answer。投票表如下所示:

投票表:

  • Id
  • PostId
  • VoteTypeId,以下值之一:

    1 - AcceptedByOriginator
    2 - UpMod
    3 - DownMod
    4 - Offensive
    5 - Favorite (if VoteTypeId = 5, UserId will be populated)
    6 - Close
    7 - Reopen
    8 - BountyStart (if VoteTypeId = 8, UserId will be populated)
    9 - BountyClose
    10 - Deletion
    11 - Undeletion
    12 - Spam
    15 - ModeratorReview  
    16 - ApproveEditSuggestion
    
  • UserId(仅在VoteTypeId为5或8时出现)

  • CreationDate
  • BountyAmount(仅在VoteTypeId为8或9时才出现)

所以基于它听起来就像它的运行方式是:

SELECT VoteTypeId FROM Votes WHERE VoteTypeId = 2 OR VoteTypeId = 3

然后根据价值,做数学:

int score = 0;
for each vote in voteQueryResults
    if(vote == 2) score++;
    if(vote == 3) score--;

即使有数百万的结果,这可能是一个非常快速的操作,因为它很简单。