mysql in与exists问题剖析

1 问题描述

​ 发布当天发现一个日志分析的sql,在测试环境上执行良好,1秒内,而在线上环境上,执行要13秒左右。

嵌套sql一步一步分析后,发现出在in上,因时间紧迫,来补不及具体分析原因,尝试使用exists来解决,秒出(0.03秒)

1.1 具体sql(in),执行时间:12.370

SELECT DISTINCT
            t2.reportdate,
            t2.uid,
            t2.datasetnum,
            t2.visualnum
        FROM
            report_dvnum t2
        WHERE
            t2.reportdate IN (
        
                SELECT
                    max(t3.DAY_SHORT_DESC) AS reportdate
                FROM
                    dim_day t3
                GROUP BY
                    t3.WEEK_ID
                UNION ALL
                    SELECT
                        date_sub(CURDATE(), INTERVAL 1 DAY) AS reportdate
            )

1.2 具体sql(exists),执行时间:0.034

SELECT DISTINCT
    t2.reportdate,
    t2.uid,
    t2.datasetnum,
    t2.visualnum
FROM
    report_dvnum t2
WHERE
EXISTS (
    SELECT
        1
    FROM
        (
            SELECT
                max(t3.DAY_SHORT_DESC) AS reportdate
            FROM
                dim_day t3
            GROUP BY
                t3.WEEK_ID
            UNION ALL
                SELECT
                    date_sub(CURDATE(), INTERVAL 1 DAY) AS reportdate
        ) t4
    WHERE
        t2.reportdate = t4.reportdate

2 事后分析

2.1 首先查看执行计划

sql(in):

1727736-20190715155428322-1347909186.png

slq(exists):

1727736-20190715155435894-225463045.png

发现exists多了索引关联的项。

2.2 in与exists区别

exists和in的使用方式:  

`#对B查询涉及id,使用索引,故B表效率高,可用大表 ``-->外小内大`

  1、exists是对外表做loop循环,每次loop循环再对内表(子查询)进行查询,那么因为对内表的查询使用的索引(内表效率高,故可用大表),而外表有多大都需要遍历,不可避免(尽量用小表),故内表大的使用exists,可加快效率;

  2、in是把外表和内表做hash连接,先查询内表,再把内表结果与外表匹配,对外表使用索引(外表效率高,可用大表),而内表多大都需要查询,不可避免,故外表大的使用in,可加快效率。

结论简单说:外小内大,用exists,外大内小用in,但是我们的情况其实是外大内小,用in是没问题。

3 问题解决

问题出在in 里面的union all上,in改成:

SELECT DISTINCT
            t2.reportdate,
            t2.uid,
            t2.datasetnum,
            t2.visualnum
        FROM
            report_dvnum t2
        WHERE
            t2.reportdate IN (
  
                select reportdate from(
                SELECT
                    max(t3.DAY_SHORT_DESC) AS reportdate
                FROM
                    dim_day t3
                GROUP BY
                    t3.WEEK_ID
                UNION ALL
                    SELECT
                        date_sub(CURDATE(), INTERVAL 1 DAY) AS reportdate) t4
            )

使用大括号把 in里面的sql括起来,就会使用索引,0.01秒执行完成。

1727736-20190715155445558-1989004654.png


转载于:https://www.cnblogs.com/ruanjianlaowang/p/11182625.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值