MySQL - 如何优化查询以计算投票数

时间:2010-09-04 12:40:34

标签: mysql query-optimization

关于实现以下结果的最佳方式的一些意见之后:

我想在我的MySQL数据库中存储可以由用户投票的产品(每个投票值+1)。我还希望能够看到用户投票的总次数。

简单来说,下表结构是理想的:

  table: product          table: user            table: user_product_vote       
+----+-------------+    +----+-------------+    +----+------------+---------+ 
| id |   product   |    | id | username    |    | id | product_id | user_id |
+----+-------------+    +----+-------------+    +----+------------+---------+
| 1  | bananas     |    | 1  | matthew     |    | 1  | 1          | 2       |
| 2  | apples      |    | 2  | mark        |    | 2  | 2          | 2       |
| .. | ..          |    | .. | ..          |    | .. | ..         | ..      |

这样我可以为每个产品或用户执行一个COUNT的user_product_vote表。

例如,当我想查看香蕉和在网页上显示的投票数时,我可以执行以下查询:

SELECT p.product AS product, COUNT( v.id ) as votes
FROM product p
LEFT JOIN user_product_vote v ON p.id = v.product_id
WHERE p.id =1

如果我的网站取得了巨大的成功(我们都可以梦想)并且我有成千上万的用户在数千种产品上投票,我担心在每个页面视图中执行这样的COUNT在服务器资源方面效率非常低。

更简单的方法是在产品表中添加一个“投票”列,每次添加投票时都会增加。

  table: product               
+----+-------------+-------+
| id |   product   | votes |
+----+-------------+-------+
| 1  | bananas     | 2     |
| 2  | apples      | 5     |
| .. | ..          | ..    |

虽然这对资源更加友好 - 但我丢失了数据(例如,由于没有投票活动记录,我不能再阻止某人投票两次)。

我的问题是:
i)我是否过度担心服务器资源,应该坚持使用三个表选项? (即我是否需要更加相信数据库处理大型查询的能力)
ii)是他们在不丢失信息的情况下实现结果的更有效方式

5 个答案:

答案 0 :(得分:6)

你永远不会过度担心资源,当你第一次开始构建应用程序时,你应该总是考虑到资源,空间,速度等,如果你的网站的流量急剧增长而你从未构建过资源那么你就开始进入问题。

至于投票制度,我个人会像这样保留投票:

table: product          table: user             table: user_product_vote       
+----+-------------+    +----+-------------+    +----+------------+---------+ 
| id |   product   |    | id | username    |    | id | product_id | user_id |
+----+-------------+    +----+-------------+    +----+------------+---------+
| 1  | bananas     |    | 1  | matthew     |    | 1  | 1          | 2       |
| 2  | apples      |    | 2  | mark        |    | 2  | 2          | 2       |
| .. | ..          |    | .. | ..          |    | .. | ..         | ..      |

原因:

首先user_product_vote不包含文本,blob等,它纯粹是整数,所以它总是占用更少的资源。

其次,您在应用程序中有更多通向新实体的门户,例如过去24小时的总投票数,过去24小时内评分最高的产品等。

举个例子:

table: user_product_vote       
+----+------------+---------+-----------+------+ 
| id | product_id | user_id | vote_type | time |
+----+------------+---------+-----------+------+
| 1  | 1          | 2       | product   |224.. |
| 2  | 2          | 2       | page      |218.. |
| .. | ..         | ..      | ..        | ..   |

一个简单的查询:

SELECT COUNT(id) as total FROM user_product_vote WHERE vote_type = 'product' AND time BETWEEN(....) ORDER BY time DESC LIMIT 20

另一件事是,如果用户在1AM投票然后再次尝试在2PM投票,您可以轻松查看他们上次投票的时间以及是否应该再次投票。< / p>

如果你坚持使用增量示例,那么你将失去很多机会。


对于您的count(),无论您对查询进行了多少优化,都无法真正大规模地发挥作用。

对于极大的用户群,您将从不同的角度查看资源使用情况,例如负载均衡器,主要是服务器设置,Apache,捕获等等,您可以对查询进行大量处理。

答案 1 :(得分:2)

  

如果我的网站取得了巨大的成功(我们都可以梦想)并且我有成千上万的用户在数千种产品上投票,我担心在每个页面视图中执行这样的COUNT在服务器资源方面效率非常低。

不要浪费你的时间来解决想象中的问题。 mysql完全能够在几分之一秒内处理数千条记录 - 这就是数据库的用途。清晰简单的数据库和代码结构远比没有人需要的神秘“优化”重要得多。

答案 2 :(得分:1)

为什么不混合搭配?只需在产品和用户表中包含最终计数,这样您就不必每次都计算并拥有投票表,这样就不会有双重发布。

编辑: 为了进一步解释,产品和用户表将有一个名为“投票”的列。每次在user_product_vote中成功插入时,都会增加相关的用户和产品记录。这样可以避免欺骗投票,并且您不必每次都运行复杂的计数查询。

编辑: 此外,我假设您已在product_id和user_id上创建了唯一索引,在这种情况下,任何重复尝试都将自动失败,您不必在插入之前检查表。您只需确保插入查询已运行,​​并且您在insert_id上的表单中获得了“id”的有效值

答案 3 :(得分:0)

您必须平衡您的网站快速执行的愿望(其中第二个架构最好)和为特定用户计算投票的能力并防止双重投票(我将选择第一个架构)。因为您只使用user_product_vote表的整数列,所以我看不出性能如何受到太大影响。与user_product_vote一起实施的多对多关系很常见。如果您确实想要为特定用户计算投票并防止双重投票,user_product_vote是我能够考虑实施它的唯一clean方式,因为任何其他方式都可能导致稀疏记录,重复记录和各种坏事。

答案 4 :(得分:0)

您不希望每次有人投票时直接使用聚合更新产品表 - 这将锁定产品行,这将影响正在使用产品的其他查询。

假设并非所有产品查询都需要包含投票列,您可以保留一个单独的产品投票表来保留运行总计,并将您的userproductvote表作为一种方法来强制执行每个产品业务规则/审核的用户投票