【问题标题】:Which is the most efficient SELECT method and why?哪个是最有效的 SELECT 方法,为什么?
【发布时间】:2013-02-23 20:08:29
【问题描述】:

考虑一个人们对他们最喜欢的颜色投票赞成 (+1) 或反对 (-1) 的网站,我有两个表格:

一个列出人们可以投票的所有颜色,第二个表格记录每个人的投票、投票的颜色以及是 +1 还是 -1。

关于获取特定颜色的总票数,在颜色表上包含总分会更有效吗?当一个人投票时,会有一个插入语句和一个更新语句:

INSERT INTO votes (colour,vote) VALUES (red,-1);
UPDATE colours SET score=score-1 WHERE colour='red';

SELECT score FROM colours WHERE colour='red';

或者在进行投票时只使用一个 INSERT 语句,然后获取您的分数会更有效吗?

SELECT SUM(vote) AS score FROM votes WHERE colour='red';

我猜是什么时候有一个非常少量的投票,那么选项#2是最好的,但是当投票表非常大时,选择#1变得更好?

是否有一些工具可以用来根据表大小等对某些 SQL 查询进行排名?

【问题讨论】:

  • 抱歉。忘了提到需要记录个人投票的表格,所以无论我采取什么选项,表格都需要在那里。
  • 您希望您的桌子有多大? 超过一个点,SUM() 会明显变慢。

标签: mysql sql


【解决方案1】:

这种优化的关键是你想要优化什么。存储总和会使插入/删除/更新需要更长的时间。计算总和会影响数据查询的性能。

如果您要对数据进行删除或更新,您很快就会发现预先计算总和的愚蠢之处。当您认为您只更改一条记录时,对数据的任何此类更改都需要修改多条记录。

不过,您的结构似乎只有插入物——顺便说一句,这是一个不错的设计选择,因为您可以看到每一个变化。在这种情况下,问题是您是要承担每个插入的开销,还是要“报告”端的开销。在某些情况下,这个问题很简单。

如果您每次查看总和时都有 1000 票,请即时计算总和。如果每次投票都有 1000 个总和,那么存储总和似乎是更有效的方法。

我的猜测是工作量介于两个极端之间。我天生的偏见是将生成的数据存储起来,然后有额外的表格用于汇总和报告。我会推荐以下两种方法之一:

(1) 仅保留交易数据并即时计算总和。排列表上的索引,使总和尽可能有效。

(2) 仅将事务保留在一个表中,并在另一个表中计算总和(使用触发器或存储过程)。这为您提供了大多数用途所需的最新值。插入应该比在每条记录上存储总和更有效(因为用户级别的表小于投票级别的表)。

您关于在投票记录中计算总和的建议通常不是我会考虑的选项。当您需要增量投票的历史时,这将是可取的。但是,如果您正在查看历史记录,那么在应用层进行 sum 计算或计算总和也是可行的选择。

【讨论】:

    【解决方案2】:

    就个人而言,我认为如果你想显示一个总分(而且我想你会想经常显示这个分数),那么随着投票表中行数的增加,你会发现聚合@ 987654321@ 查询将花费越来越长的时间并且不能很好地扩展。

    此外,如果您计划实现仅显示得分为 100 或更高的颜色的查询,那么聚合将使查询更简单、更快捷。

    使用分数列的另一个优点是,如果在将来某个日期您想清理votes 表(例如,如果它变得太大),那么您可以这样做并且不会丢失颜色分数。

    我不认为这是过早的优化,我认为这是在设计一个考虑到规模的系统,所以我要做的是创建一些样本数据集,这些数据集包含您每分钟的实际投票数、颜色和查询数d 期望并运行一些性能测试来评估什么是更好的方法,因为现在选择正确的方法更容易(读起来更便宜),而不是在事情开始出错时修复它。

    【讨论】:

    • 为了更好地了解,可以使用BENCHMARK() 函数来确定它是否真的会达到明显差异的程度。
    【解决方案3】:

    您是在过早地优化还是这是一个真正的问题?

    第一种方法可能更快,但您为了优化而更改了域模型。只要您知道自己在做什么以及它给您带来什么不利条件就可以了(例如,可能需要在所有使用投票的地方更新两个表,从而导致不同步)

    但您可以考虑其他选择。例如,如果颜色的数量不是那么大,您可以为它们的评级建立一个缓存。这将保持简单的模型、简单的评级机制并提供您需要的速度,减去一些内存;)

    【讨论】:

      【解决方案4】:

      这两个查询之间的性能差异是微不足道的。您应该根据要保留的信息确定结构。

      如果您只需要总分,则使用

      UPDATE colours SET score=score-1 WHERE colour='red';
      

      这会非常快,因为表 colours 只会有几行。

      另一方面,存储每个用户的投票可能是有原因的(例如确保他们不会投票两次)。在这种情况下,为每个投票插入一行。

      INSERT INTO votes (colour,vote,user_id) VALUES (red,-1);
      

      但是不要仅仅因为你认为它会更快就创建一个不必要的行结构。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-08-31
        • 1970-01-01
        • 1970-01-01
        • 2023-03-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多