【问题标题】: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 个表格。向我展示关于该查询的“解释”也会让我深入了解可能缺少索引的位置。

标签: php sql mysql optimization


【解决方案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,也不知道在那里应该避免这种情况。
    猜你喜欢
    • 1970-01-01
    • 2021-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-18
    • 1970-01-01
    • 2012-10-06
    相关资源
    最近更新 更多