【问题标题】:MySQL GROUP BY performance issueMySQL GROUP BY 性能问题
【发布时间】:2010-01-22 18:14:26
【问题描述】:

这是我正在执行的查询(没有一些不相关的联接):

SELECT a.*, c.id
FROM a
LEFT OUTER JOIN b ON a.id = b.id_anunciante
LEFT OUTER JOIN c ON c.id = b.id_rubro
GROUP BY a.id

“a”的每一行都与“b”中的1到5行链接。

问题在于 GROUP BY 存在性能问题(使用 GROUP BY 比不使用它需要 10 倍或更多)。我只需要检索“a”中每个成员的一行。

我怎样才能加快速度?

编辑:我需要能够按 a.id 和/或 c.id 进行过滤。我应该得到的结果集是每个“a”的“有效”成员只有 1 行,这意味着与约束匹配的行。不应返回与过滤器不匹配的行。 在我的原始查询中,这将是这样完成的:

SELECT a.*, c.id
FROM a
LEFT OUTER JOIN b ON a.id = b.id_anunciante
LEFT OUTER JOIN c ON c.id = b.id_rubro
WHERE c.id = 1
OR a.id = 1
GROUP BY a.id

a.id、b.id_anunciante、b.id_rubro、c.id都是索引。

【问题讨论】:

    标签: mysql performance group-by


    【解决方案1】:
    SELECT  a.*,
            (
            SELECT  c.id
            FROM    b
            JOIN    с
            ON      c.id = b.id_rubro
            WHERE   b.id_anunciante = a.id
            -- add the ORDER BY condition to define which row will be selected.
            LIMIT 1
            )
    FROM    a
    

    b (id_anunciante) 上创建索引以便更快地工作。

    更新:

    这里不需要OUTER JOINs

    将您的查询重写为:

    SELECT  a.*, c.id
    FROM    a
    JOIN    b
    ON      b.id_anunciante = a.id
    JOIN    c
    ON      c.id = b.id_rubro
    WHERE   a.id = 1
    UNION ALL
    SELECT  a.*, 1
    FROM    a
    WHERE   EXISTS
            (
            SELECT  NULL
            FROM    c
            JOIN    b
            ON      b.id_rubro = c.id
            WHERE   c.id = 1
                    AND b.id_anunciante = a.id
            )
    

    【讨论】:

    • 感谢您的回答!如果我需要按 c.id AND/OR a.id 过滤怎么办?我不能那样做,可以吗?
    • @macaco:当然可以。只需将WHERE 条件添加到外部查询以过滤a,并添加到子查询以过滤c
    • 我尝试在子查询“WHERE b.id_anunciante = a.id AND c.id = 1”中按 c.id 过滤,但我得到了相同数量的行和不应该的行用 NULL 填充子查询列。
    • @macaco:是的,这就是它应该表现的方式。 LEFT JOINs(在您的原始查询中使用)的要点是为缺少的行返回 NULL。如果这不是您所期望的,您能否使用示例数据和您想要获得的结果集更新您的问题?
    • 我不应该在子查询中获取带有 NULL 的行。我已经更新了这个问题。再次感谢!
    【解决方案2】:

    添加 ORDER BY NULL 以避免 MySQL 在进行分组时执行的隐式排序。

    我想您在 a.id、b.id_anunciante、b.id_rubro 和 c.id 上有索引/PK?如果您的 mysql 版本无法进行索引合并,我想您可以尝试在 (b.id_anunciante, b.id_rubro) 上添加复合索引。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-06-19
      • 2010-11-10
      • 2022-06-14
      • 1970-01-01
      • 2019-02-11
      • 1970-01-01
      • 1970-01-01
      • 2017-10-20
      相关资源
      最近更新 更多