【问题标题】:MySQL- Counting rows VS Setting up a counterMySQL- 计算行数 VS 设置计数器
【发布时间】:2014-06-26 02:10:51
【问题描述】:

我有 2 张桌子 posts<id, user_id, text, votes_counter, created>votes<id, post_id, user_id, vote>。这里的表格投票可以是 1(赞成)或 -1(反对)。现在,如果我需要获取帖子的总票数(赞成票 - 反对票),我可以通过 2 种方式完成。

  1. 使用 count(*) 计算 votes 表中对该帖子的赞成和反对的数量,然后进行数学运算。
  2. 设置一个计数器列votes_counter,并在每次用户赞成或反对时增加或减少它。然后简单地提取votes_counter

我的问题是哪个更好,在什么条件下。我所说的条件是指可扩展性、峰值时间等因素。

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

是否有第三种方式比这两种方式更好且实施起来更简单?

【问题讨论】:

  • "votes_counter 列可能会死锁,太多用户试图更新计数器" --- 为什么这里应该是死锁?
  • @zerkms 我的意思是技术上没有僵局!假设有 1000 名用户试图每秒对一篇帖子进行投票。但是数据库服务器无法在一秒钟内处理 1000 次操作。这就是我所说的那种情况。
  • 当您有 1000 个用户同时在您的网站上执行某项操作时 - 增加单个计数器将不是您需要担心的事情。
  • @zerkms 好吧,这是我的大学模拟项目。真正的每秒 1K 用户是一件大事!

标签: mysql sql


【解决方案1】:

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

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

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

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

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

【讨论】:

    【解决方案2】:

    因为这听起来很像 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--;
    

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

    【讨论】:

    • 这在 Stack Overflow 上并没有那么快,因为他们也缓存了分数。如果您扩大该操作需要一段时间的分数,因此该操作仅适用于 2k+ 用户
    猜你喜欢
    • 2013-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-05
    • 2018-08-08
    • 1970-01-01
    相关资源
    最近更新 更多