8

考虑一个人们对他们最喜欢的颜色投票赞成(+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 查询进行排名?

4

4 回答 4

4

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

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

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

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

于 2013-03-08T10:22:55.450 回答
1

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

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

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

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

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

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

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

于 2013-03-08T10:10:29.140 回答
0

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

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

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

于 2013-03-08T10:15:04.030 回答
0

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

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

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

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

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

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

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

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

于 2013-03-08T12:07:41.113 回答