深入了解查询优化

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_croncron_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,也不知道在那里应该避免这种情况。

以上是关于深入了解查询优化的主要内容,如果未能解决你的问题,请参考以下文章

MySQL查询优化之explain的深入解析

深入浅出的 SQL Server 查询优化

如何针对 db2 数据库优化 SQL/Python 选择查询?

掌握查询利器 深入理解PostgreSQL索引原理与优化

深入浅出 SQL 优化器原理

Apache Kylin 深入Cube和查询优化