MySQL - 如何优化查询以计算选票
Posted
技术标签:
【中文标题】MySQL - 如何优化查询以计算选票【英文标题】:MySQL - how to optimize query to count votes 【发布时间】:2010-09-04 12:40:33 【问题描述】:就获得以下结果的最佳方法发表了一些意见:
我想在我的 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 |
| .. | .. | | .. | .. | | .. | .. | .. |
这样,我可以为每个产品或用户对 user_product_vote 表进行 COUNT。
例如,当我想查找香蕉和要在网页上显示的投票数时,我可以执行以下查询:
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) 是他们在不丢失信息的情况下实现结果的更有效方式
【问题讨论】:
你遇到的另一个问题是你可能从来没有拥有过一个获得大量流量的网站,所以你不确定 php / mysql 的功能,我向你保证 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 |
| .. | .. | | .. | .. | | .. | .. | .. |
原因:
首先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
投票,您可以轻松查看他们上次投票的时间以及是否应该允许他们再次投票。
如果你坚持你的增量示例,你会错过很多机会。
关于您的count()
,无论您如何优化查询,它都不会真正产生大规模的影响。
由于用户群非常庞大,您的资源使用情况会从不同的角度来看待,例如负载平衡器,主要是服务器设置、Apache、捕获等,您可以对查询做的只有这么多。
【讨论】:
【参考方案2】:如果我的网站取得了巨大的成功(我们都可以梦想),并且我有成千上万的用户对数千种产品进行投票,我担心每次页面浏览都执行这样的 COUNT 会在服务器资源方面非常低效。
不要浪费时间解决想象中的问题。 mysql 完全能够在几分之一秒内处理数千条记录——这就是数据库的用途。干净简单的数据库和代码结构远比没有人需要的神话般的“优化”重要得多。
【讨论】:
【参考方案3】:为什么不将两者混合搭配?只需在 product 和 users 表中都有最终的 count ,这样就不用每次都要数,有 votes 表,这样就不会重复发帖了。
编辑: 为了进一步解释,product 和 user 表将有一个名为“votes”的列。每次在 user_product_vote 中插入成功时,增加相关的用户和产品记录。这样可以避免重复投票,您也不必每次都运行复杂的计数查询。
编辑: 此外,我假设您已经在 product_id 和 user_id 上创建了唯一索引,在这种情况下,任何重复尝试都会自动失败,您不必在插入前检查表。您将只是确保插入查询运行并且您在 insert_id 上的表单中获得了“id”的有效值
【讨论】:
【参考方案4】:您必须平衡网站快速执行的愿望(第二种模式最好)和计算特定用户投票和防止重复投票的能力(我会选择第一种模式)。因为您只对user_product_vote
表使用整数列,所以我看不出性能会受到多大影响。多对多关系很常见,正如您使用user_product_vote
实现的那样。如果您确实想计算特定用户的投票并防止重复投票,user_product_vote
是我能想到的唯一实现它的 clean
方式,因为任何其他方式都可能导致记录稀疏、重复记录和各种不良记录东西。
【讨论】:
【参考方案5】:您不希望每次有人投票时都直接使用聚合更新产品表 - 这将锁定产品行,进而影响正在使用产品的其他查询。
假设并非所有产品查询都需要包含投票列,您可以保留一个单独的 productvotes 表,该表将保留运行总数,并保留您的 userproductvote 表作为根据产品业务规则强制执行用户投票/和审计的手段.
【讨论】:
以上是关于MySQL - 如何优化查询以计算选票的主要内容,如果未能解决你的问题,请参考以下文章