【问题标题】:MySQL get top 10 items matching other table to group themMySQL 获取与其他表匹配的前 10 个项目以对它们进行分组
【发布时间】:2014-03-18 22:56:42
【问题描述】:

也许标题没有很好地解释。 我有这个:

users (id, name)
-----------------------
|  1  |  User 1   | US |
|  2  |  User 2   | US |
|  3  |  User 3   | FR |
|  4  |  User 4   | IT |
|  5  |  User 5   | US |
| ... |  ......   | .. |
------------------------

games (game_id, user_id)
---------------
|  1 |   2    |
|  2 |   4    |
|  3 |   1    |
|  4 |   6    |
| ...|  ...   |
---------------

我需要的是让顶级国家玩游戏,所以回答如下:

1   US   145 games
2   FR    25 games
3   IT    12 games
...
up to 10 results

我的解决方案是这样,但是太慢了(有数百万条记录)

select 
  distinct(user.country), 
  count(*) as counter 
from games
  inner join user on games.user_id = user.id 
group by user.country 
order by counter DESC
limit 10

【问题讨论】:

  • DISTINCT 是关键字,而不是函数。 user.country 周围的括号是不必要的;它们不影响声明。实际上,这个查询不需要DISTINCT 关键字,因为有一个GROUP BY user.country 子句。
  • 我建议您使用EXPLAIN 来验证查询是否使用合适的索引进行 JOIN 操作。您可以使用EXPLAIN SELECT ... 的输出更新您的问题。快速的答案是为 MySQL 提供合适的索引来使用,但是在不知道 MySQL 在做什么的情况下给出这个答案是没有意义的。
  • 每个用户大概有多少游戏?表上有哪些索引?
  • 下次当您需要性能方面的帮助时,还要在问题中显示explain plan

标签: mysql performance inner-join


【解决方案1】:

为了获得最佳性能,MySQL 需要有合适的可用索引。

对于此查询,您似乎需要这些索引:

... ON users (country, id)

... ON games (user_id) 

解释

您想要一个以country 作为前导列的索引,因此 MySQL 可以使用该索引来执行 GROUP BY 操作,而不是使用昂贵的“使用文件排序”操作。

将用户id 列用作该索引中的辅助列意味着它将是一个覆盖索引,并且MySQL 不需要访问基础表中的页面。

user_id为前导列的游戏表上的索引意味着MySQL可以使用该索引来获取计数。

我们希望 MySQL 在 EXPLAIN 的 Extra 列中显示“使用索引”。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-06
    • 1970-01-01
    • 2018-10-24
    • 1970-01-01
    相关资源
    最近更新 更多