深入了解查询优化
Posted
技术标签:
【中文标题】深入了解查询优化【英文标题】:Insight on a query optimization 【发布时间】:2009-05-21 17:25:36 【问题描述】:我在这里尝试基本上找到具有某项活动所针对的运动和地区的用户。在访问 [users] 表中,大约有 17K 用户。每个人都可以有一定数量的运动兴趣和一个地区。
这里的查询会查找至少拥有一项运动和一个地区的每个用户,这些用户至少是通过活动定位的。当我们选择每个 em 时,Sports 可以达到 75 [不太好用 IN 查询]。
SELECT a.user, pp.courriel
FROM acces a
LEFT JOIN acces_profil_sport ap ON ap.id = a.id
LEFT JOIN profil_perso pp ON pp.id = a.id
WHERE ap.sport_id IN
(
SELECT ac.sport_id
FROM activite_sport ac
RIGHT JOIN activite a ON a.activite_id = ac.activite_id AND a.is_cron = 1 AND a.cron_processed = 0
)
AND pp.region_id IN
(
SELECT ar.region_id
FROM activite_region ar
RIGHT JOIN activite a ON a.activite_id = ar.activite_id AND a.is_cron = 1 AND a.cron_processed = 0
)
GROUP BY a.id
如果我删除运动查找,查询需要大约 30 秒才能运行。否则它需要很长时间并且使用mysql的大约99%的proc。
有什么帮助吗?
[编辑:表结构]
访问权限:id(主键)、用户、perso_
id(profil_
perso[perso_
id] 的键/外键)[some-other-fields]
profil_
perso : perso_
id (primary key) courriel, region_
id, id (访问的外键[id]) [其他一些字段]
acces_
profil_
sport : id/sport_
id (双主键), niveau_
id (双键与sport_
id)
【问题讨论】:
您能否列出您正在使用的表以及列是什么? 您的表是否正确编入索引?虽然这个查询不是很好,但在您正在使用的相对较小的数据集上,它似乎不应该花费那么。 您没有在该编辑中给我们 2 个表格。向我展示关于该查询的“解释”也会让我深入了解可能缺少索引的位置。 【参考方案1】:我怀疑您的索引有误。如果您打印出 explain select...,我可以更好地对此发表评论。此外,我很好奇您为什么要进行左/右连接和子选择。
在我看来,这些都应该是正常的连接,因为两个左连接只有在它们存在时才有效。如果它们为 null,则由于所需的子选择匹配,您将不会得到一行。
至于右连接,您需要那里的 ar 位,它不是右侧的一部分。我要么删除它们,要么也将它们直接连接起来。我假设由于您正在检查看起来像是未处理的 cron 工作的内容,因此您希望保留它们。
SELECT a.user, pp.courriel
FROM acces
JOIN acces_profil_sport ap ON ap.id = a.id
JOIN profil_perso pp ON pp.id = a.id
JOIN activite_sport ac ON ac.sport_id = ap.sport_id
JOIN activite a1 ON a.activite_id = ac.activite_id AND a.is_cron = 1 AND a.cron_processed = 0
JOIN activite_region ar ON ar.region_id = pp.region_id
JOIN activite a2 ON a.activite_id = ar.activite_id AND a.is_cron = 1 AND a.cron_processed = 0
【讨论】:
它将由 cron 每晚处理......有点像邮件列表 Neato,几乎就是我要建议的,不错的解决方案! 你也需要一个独特的吗?例如在 acces_profile_sport 中的多行具有相同的 'id' 值...用户附加到多项运动?给定区域的多项活动? 我添加了一个 GROUP BY 语句,像一个魅力一样工作。 [虽然我很想知道 distinct 和 group by 之间最快的是什么 他们都做不同的事情。一种用于形成聚合,另一种用于消除重复。而且,答案总是衡量、衡量、衡量。【参考方案2】:你有is_cron
和cron_processed
的索引吗?它可以帮助加快速度。
【讨论】:
【参考方案3】:SELECT acces.user, courriel
FROM acces
JOIN profil_perso ON acces.id = profil_perso.id
WHERE EXISTS (SELECT 1 FROM acces_profil_sport JOIN activite_sport on acces_profil_sport.sport_id = activite_sport.sport_id JOIN activite ON activite.activite_id = activite_sport.activite_id WHERE is_cron = 1 AND cron_processed = 0 AND acces_profil_sport.id = profil_perso.id)
AND EXISTS (SELECT 1 FROM activite_region JOIN activite ON activite_region.activite_id = activite.activite_id WHERE is_cron = 1 AND cron_processed = 0 AND activite_region.region_id = profil_perso.region_id);
【讨论】:
为什么要使用连接解决问题的子选择?子选择往往会产生更多开销,在某些情况下,运行速度会明显变慢。 正如我在上面的评论中提到的,我认为只使用连接可能需要“不同”。在大多数数据库中使用“where exists”连接表效果很好,尽管我承认我不经常使用 MySQL,也不知道在那里应该避免这种情况。以上是关于深入了解查询优化的主要内容,如果未能解决你的问题,请参考以下文章