mysql in子查询的优化

怎甘沉沦 提交于 2019-11-27 22:37:48

项目遇到一个MySQL查询特别慢的语句:

SELECT *
FROM (
    SELECT DISTINCT t.vc_date, t.c_bankno, t.vc_bankacco, t.vc_moneytype, t.en_totalbala

    FROM tbankaccobala t

    WHERE 1 = 1
        AND t.id IN (
            --   这个查询需要3s:
            -- SELECT SUBSTRING_INDEX(GROUP_CONCAT(id ORDER BY d_importtime DESC), ',', 1)
            -- FROM tbankaccobala
            -- GROUP BY vc_bankacco
            -- 但改成下面这样只要0.006s:
            SELECT hhhh from(
                SELECT SUBSTRING_INDEX(GROUP_CONCAT(id ORDER BY d_importtime DESC), ',', 1) as hhhh
                FROM tbankaccobala
                GROUP BY vc_bankacco
            ) as sbstr
            -- 对IN的子查询做二次查询,或者把IN改为JOIN都可以解决IN速度奇慢的问题
        )
) t
WHERE 1 = 1

上面语句空行处省略了一系列的其他表和 INNER JOIN 语句。

原语句导致前端页面10秒左右才有响应(但MySQL执行显示要4.6秒,phpMyAdmin也是10秒左右响应,为何?)

一开始怀疑是多表的JOIN操作导致速度变慢,但删去JOIN变成上面这段注释掉的语句之后,速度依然非常慢,显示要3s,

于是猜测 IN 才是导致速度变慢的主要因素,把IN的子查询用二次查询包起来之后时间就降低到0.006s!

EXPLAIN 未优化的语句:

id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY ALL NULL NULL NULL NULL 1713
2 DERIVED t ALL NULL NULL NULL NULL 1713 Using where; Using temporary
3 DEPENDENT SUBQUERY tbankaccobala ALL NULL NULL NULL NULL 1713 Using filesort

(相关子查询是使用外部查询中的值的子查询)

EXPLAIN 优化的语句:

id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY ALL NULL NULL NULL NULL 1713
2 DERIVED ALL NULL NULL NULL NULL 1713 Using where; Start temporary; Using temporary
2 DERIVED t eq_ref PRIMARY PRIMARY 98 sbstr.hhhh 1 Using where; End temporary
4 DERIVED tbankaccobala ALL NULL NULL NULL NULL 1713 Using filesort

我的理解:优化前,子查询是相关子查询,对于外部产生的每个值,都要执行一次子查询;优化后,子查询不再是相关子查询,只需要执行一次子查询并缓存中间结果,外部查到的每个值去缓存的中间结果遍历就行了。

深入理解MySql子查询IN的执行和优化

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!