使用中间表优化 MySQL Join 和 Group By

Posted

技术标签:

【中文标题】使用中间表优化 MySQL Join 和 Group By【英文标题】:Optimizing MySQL Join and Group By with intermediate table 【发布时间】:2016-01-09 00:17:21 【问题描述】:

简化但我有三个表:

用户(user_id、team_id) 结果(user_id,结果) user_signups (user_id, team_id, event_id)

results.user_id 是外键。

表格中有大量行。如果我这样做了

select sum(result)
from results
inner join users on users.id = results.user_id
group by team_id

速度很快。 “解释”的结果有 150k 行,用户有 1 行。

如果我这样做

select sum(result)
from results
inner join user_signups on user_signups.user_id = results.user_id
where event_id = 1
group by team_id

它非常慢(从 1 秒到 14 秒)。 “解释”的结果有 28 行,user_signups 有 5345 行。

我尝试过的事情:

user_signups 上 event_id 和 user_id 的唯一索引。

user_signups 上 event_id、user_id、team_id 的索引。

改写为

select sum(result)
from results
inner join (select * from user_signups where event_id = 1) user_signups on user_signups.user_id = results.user_id
group by team_id

改写为

select sum(result)
from results
inner join users on users.id = results.user_id
inner join user_signups on user_signups.user_id = users.id
where event_id = 1
group by user_signups.team_id

还有其他建议吗?

【问题讨论】:

请确定每个表上的现有索引,并建议您在问题中显示解释计划结果,示例数据和预期结果也会有所帮助(也许设置一个 sqlfiddle?sqlfiddle.com) 去阅读一些关于mysql查询优化的其他问题。通常,当他们没有架构的详细信息和解释计划时,他们会被否决或回答不佳。 请为每张桌子提供SHOW CREATE TABLE 【参考方案1】:

通过对 team_id 进行分组,我假设您希望 results 中的每条记录都有一行。

这就是你要找的吗?

SELECT *, sum(result) FROM results
LEFT JOIN users ON (users.user_id=results.user_id)
LEFT JOIN user_signups ON (user_signups.users_id=users.user_id)
GROUP BY table.field

从这里,您可以根据自己的喜好进行分组。此结构假定您的大部分数据将出现在结果表中,并将用户连接到结果表,并将 user_signups 连接到用户表。

【讨论】:

你真的相信这样会更快吗? 如果 user_id 字段被正确索引,它应该。 没有。 最好 LEFT JOIN 将与 INNER JOIN 一样长,但在大多数情况下它会慢得多,并且会返回一个不同的值 这取决于您尝试获取的结果集。如果您主要关心的是结果的总和,那么使用左连接将首先查找结果,然后将用户连接到该表。所以实际上在这种情况下它会更快。 不,不会的。如果您不相信我,请尝试一下。这不是您在此处提供的查询。【参考方案2】:

在 user_signups 表中的 (event_id, user_id, team_id) 上创建多列索引并尝试运行以下查询。 如果这不起作用,请在此处发布您的解释。

select sum(result) from results inner join(select
event_id,user_id,team_id from user_signups where event_id = 1)
user_signups on user_signups.user_id = results.user_id group by
team_id

【讨论】:

以上是关于使用中间表优化 MySQL Join 和 Group By的主要内容,如果未能解决你的问题,请参考以下文章

mysql性能优化2

MySQL45讲join语句优化

MySQL中inner join 和 cross join 的区别

MySQL的JOIN:JOIN优化实践之内循环的次数

MySQL系列6 - join语句的优化

MySQL系列6 - join语句的优化