使用子查询优化 mysql 查询

Posted

技术标签:

【中文标题】使用子查询优化 mysql 查询【英文标题】:Optimize mysql query with subqueries 【发布时间】:2014-07-31 04:26:40 【问题描述】:

下面是 mysql 查询,我可以通过它获得不想要的结果

但是有什么办法可以优化查询

SELECT users.*,
    (SELECT country_name FROM country WHERE country_code = users.country_code)
        AS country_name,
    (SELECT zone_name FROM timezone WHERE timezone_id = users.timezone_id)
        AS zone_name,
    (SELECT GROUP_CONCAT(list_name)
     FROM list LEFT JOIN user_list ON user_list.list_id = list.list_id
     WHERE user_list.user_id = users.user_id AND user_list.status = "active")
        AS groups,
    (SELECT GROUP_CONCAT(promotion_name)
     FROM promotion LEFT JOIN promotion_user ON promotion_user.promotion_id = promotion.promotion_id
     WHERE promotion_user.user_id = users.user_id AND promotion_user.status = "active")
         AS promotions,
    (SELECT GROUP_CONCAT(full_name)
     FROM users u LEFT JOIN promotion_user ON promotion_user.promotor_id = u.user_id
     WHERE promotion_user.user_id = users.user_id AND promotion_user.status = "active")
         AS promotors
FROM users WHERE client_id = '2' AND status != 'deleted'
ORDER BY user_id desc
LIMIT 50 OFFSET 0

解释输出是

可能的钥匙 id select_type table type _keys key _len ref rows Extra 1 PRIMARY 用户索引 NULL PRIMARY 4 NULL 1045612 使用 where 6 DEPENDENT SUBQUERY Promotion_user ALL NULL NULL NULL NULL 16159 使用 where 6 相关子查询 u eq_ref PRIMARY PRIMARY 4 [1] 1 NULL 5 DEPENDENT SUBQUERY Promotion_user ALL NULL NULL NULL NULL 16895 使用 where 5 DEPENDENT SUBQUERY 提升 ALL PRIMARY NULL NULL NULL 4 使用 where;使用连接缓冲区(块嵌套循环) 4 相关子查询列表 ALL PRIMARY NULL NULL NULL 1592 NULL 4 DEPENDENT SUBQUERY user_list ALL NULL NULL NULL NULL 159852 使用where;使用连接缓冲区(块嵌套循环) 3 DEPENDENT SUBQUERY 时区 eq_ref PRIMARY PRIMARY 4 [2] 1 NULL 2 DEPENDENT SUBQUERY country ALL NULL NULL NULL NULL 239 使用 where [1] test.promotion_user.promoter_id [2] test.promotion_user.promoter_id

【问题讨论】:

发布查询的 EXPLAIN 输出会有所帮助。 还显示表的 DDL(或告诉我们哪些列被索引,存在哪些关系等) 考虑到复杂性 Fiddle 会很好。 你能张贴表声明。查看您发布的 EXPLAIN 输出,您似乎在表上几乎没有有用的索引。缺少索引可能会大大减慢速度。 【参考方案1】:

我会尝试使用非相关子查询。但是,由于您只带回单个用户的详细信息(因此可能是单行),这可能无济于事。除了可能消除一个子查询之外。

类似的东西(未经测试,因为没有数据定义或数据示例)

SELECT `users`.*,
    country.country_name,
    timezone.zone_name,
    sub_groups.groups,
    sub_promotors.promotions,
    sub_promotors.promotors
FROM `users`
INNER JOIN country
ON country.country_code = users.country_code
INNER JOIN timezone
ON timezone.timezone_id = users.timezone_id
INNER JOIN 
(
    SELECT promotion_user.user_id, GROUP_CONCAT(full_name) AS promotors, GROUP_CONCAT(promotion_name) AS promotions
    FROM users u
    LEFT JOIN promotion_user ON promotion_user.promotor_id = u.user_id
    WHERE promotion_user.status = "active"
    GROUP BY promotion_user.user_id
) AS sub_promotors
ON sub_promotors.user_id = users.user_id
INNER JOIN 
(
    SELECT user_list.user_id, GROUP_CONCAT(list_name) AS groups
    FROM list
    LEFT JOIN user_list ON user_list.list_id = list.list_id
    WHERE user_list.status = "active"
    GROUP BY user_list.user_id
) AS sub_groups
ON sub_groups.user_id = users.user_id
WHERE users.client_id = '2'
AND users.status != 'deleted'
ORDER BY users.user_id 
DESC LIMIT 50 OFFSET 0

相关子查询有效地强制 MySQL 为每个返回的行执行一次。将这些更改为连接的非相关子查询意味着它们可以对所有返回的行执行一次。不利的一面是,就 MySQL 中的索引而言,加入子查询的优化很差。

如果发起人全名等是唯一的,您也许可以删除子查询。

【讨论】:

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

MySQL5.7性能优化系列——SQL语句优化——使用物化策略优化子查询

MySQL 查询优化 - 子查询 & 使用 where;使用临时的;使用文件排序

mysql的子查询中有统计语句 我该如何优化

那个mysql 子查询和连接查询 一般常用哪个 谁效率高些

MySQL:子查询检查超过 14000 行的子查询优化问题

MySQL 子查询优化 - where not in(子查询)