【问题标题】:Left join with group_concat is too slow与 group_concat 左连接太慢
【发布时间】:2011-09-14 12:47:52
【问题描述】:

我有 2 张桌子:

users (id, firstname, lastname, etc)
users_to_groups (user_id(index), group_id(index))

我想做一个返回如下记录的查询:

firstname   lastname    groups
John        Smith       1,2,3,5
Tom         Doe         3,5

我使用的是 GROUP_CONCAT 函数,目前我的查询是:

SELECT * FROM users
LEFT OUTER JOIN 
(
     SELECT user_id, group_concat(group_id) FROM users_to_groups GROUP BY user_id
) AS i
ON users.id = i.user_id

它可以工作,但速度很慢。我在组表中有 40k 个用户和 260k 条记录。 看起来查询不使用索引并为每个用户遍历所有 260k 行。

有什么方法可以加快速度吗?这需要 3 多分钟,但我认为不应该。

谢谢!

【问题讨论】:

  • 内部查询需要多长时间才能执行,如果您自己运行它?你能发布 EXPLAIN 的输出吗?
  • 请发布您对查询的解释计划,以便人们可以帮助找出不使用索引的原因。基本上看起来您正在为所有用户请求信息(任何地方都没有 WHERE 子句),因此无论如何都必须扫描所有数据。如果单独运行内部选择需要多长时间?

标签: mysql sql


【解决方案1】:

尝试:

SELECT
    u.user_id, u.firstname, u.lastname, group_concat(g.group_id)
    FROM users                           u
        LEFT OUTER JOIN users_to_groups  g ON u.id on g.user_id
    GROUP BY u.id, u.firstname, u.lastname

【讨论】:

    【解决方案2】:

    不是左连接,而是子选择使您的查询变慢。 MySQL 在子选择方面真的很糟糕。

    这可能更快:

    SELECT 
      u.id, u.firstname, u.lastname,
      group_concat(ug.group_id) AS groups
    FROM
      users u
      LEFT JOIN users_to_groups ug ON ug.user_id = u.id
    GROUP BY 
       u.id, u.firstname, u.lastname
    

    【讨论】:

    • 太棒了!这真的很快。非常感谢!
    • 有人知道如何添加第二个连接表吗?它被称为“时事通讯”,我也想像组表一样用逗号分隔,如果可能的话,保留两者。我尝试在第一个左连接之后添加另一个左连接,但它重复了两个连接列。
    • 这完全是一个不同的问题。但我会给你一个提示:group_concat(DISTINCT ug.group_ID)。它允许您只返回每个 id 一次。在这种情况下,子选择会更好,但速度仍然较慢。
    猜你喜欢
    • 1970-01-01
    • 2013-08-25
    • 1970-01-01
    • 1970-01-01
    • 2018-09-04
    • 1970-01-01
    • 2021-03-21
    • 2017-11-28
    • 2015-05-28
    相关资源
    最近更新 更多