我正在尝试提供一项功能,让我可以显示 friend 查看最多的页面。我的 friend 表有 570 万行, View 表有 530 万行。目前我只想对这两个表运行查询并找到一个人的 friend 查看次数最多的 20 个页面 ID。
这是我现在的查询:
SELECT page_id
FROM `views` INNER JOIN `friendships` ON friendships.receiver_id = views.user_id
WHERE (`friendships`.`creator_id` = 143416)
GROUP BY page_id
ORDER BY count(views.user_id) desc
LIMIT 20
这是解释的样子:
+----+-------------+-------------+------+-----------------------------------------+---------------------------------+---------+-----------------------------------------+------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------------+------+-----------------------------------------+---------------------------------+---------+-----------------------------------------+------+----------------------------------------------+
| 1 | SIMPLE | friendships | ref | PRIMARY,index_friendships_on_creator_id | index_friendships_on_creator_id | 4 | const | 271 | Using index; Using temporary; Using filesort |
| 1 | SIMPLE | views | ref | PRIMARY | PRIMARY | 4 | friendships.receiver_id | 11 | Using index |
+----+-------------+-------------+------+-----------------------------------------+---------------------------------+---------+-----------------------------------------+------+----------------------------------------------+
views 表有一个主键(user_id, page_id),你可以看到它正在被使用。友谊表的主键为 (receiver_id, creator_id),二级索引为 (creator_id)。
如果我在没有分组依据和限制的情况下运行此查询,则该特定用户大约有 25,000 行 - 这很正常。
在最近的实际运行中,此查询也执行了 7 秒,这对于 Web 应用程序中的正常响应来说太长了。
我想知道的一件事是我是否应该将二级索引调整为 (creator_id, receiver_id)。我不确定这会带来很大的性能提升。我今天可能会根据这个问题的答案来尝试。
您能看出有什么方法可以重写查询以使其变快吗?
更新:我需要对其进行更多测试,但如果我不在数据库中进行分组和排序,但之后在 ruby 中进行,那么我讨厌的查询似乎会更好。总时间要短得多——看起来大约缩短了 80%。也许我的早期测试存在缺陷 - 但这绝对值得更多调查。如果这是真的 - 那么 Mysql 在做什么?
最佳答案
据我所知,进行这种“闪电般快速”查询的最佳方法是创建一个汇总表,以跟踪每个创建者每页的好友页面浏览量。
您可能希望通过触发器使其保持最新。然后你的聚合已经为你完成了,这是一个简单的查询来获得最多查看的页面。您可以确保在汇总表上有适当的索引,这样数据库甚至不必进行排序即可获得最多的浏览量。
汇总表是在以读取为主的环境中保持聚合类型查询良好性能的关键。您预先完成工作,当更新发生时(不频繁)然后查询(频繁)不需要做任何工作。
如果您的统计数据不必是完美的,并且您的写入实际上相当频繁(页面浏览量可能就是这种情况),您可以在内存中批量处理 View 并在后台处理它们,这样 friend 们在查看页面时不必费力使汇总表保持最新。该解决方案还减少了对数据库的争用(更少的进程更新汇总表)。
关于mysql - 优化两个大表上的简单查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1004672/