LEFT JOIN 比 INNER JOIN执行更快

背景

        写了一段sql,一个表自关联了三次,测试后发现如果用left join不到一秒可以查询出数据,如果用inner join却查询几分钟都不会出数据。

表格结构

        如下所示,这是一张用户的报表浏览记录表,其中CLICK_TIME创建了索引字段,表格总数据量20w条左右

 查询sql

        下面sql想要查询每个用户一周之内每天相比较点击报表的最早时间和最晚时间,以及所点击的报表的明细。

SELECT c.wx_user_id AS wxUserId, c.menu_name AS earliestMenu, c.click_time AS earliestTime,d.menu_name lastMenu,d.click_time lastTime,b.num num,b.max maxTime,b.min minTime,'0' menu_type
            FROM (
                -- 得到报表浏览最早的时间和浏览最晚的时间
                SELECT a.wx_user_id, count(1) num
                    , max(to_CHAR(a.click_time, 'HH24:MI:SS')) AS max
                    , min(to_CHAR(a.click_time, 'HH24:MI:SS')) AS min
                FROM MOBILE_DOOR_MENU_CLICK_LOG a
                WHERE a.click_time >= trunc(SYSDATE-4) and a.click_time <= TO_DATE(TO_CHAR(SYSDATE, 'yyyy-MM-dd HH24'),'yyyy-MM-dd HH24:MI:SS')
                    
                GROUP BY a.wx_user_id
            ) b
                -- 根据用户名和浏览时间进行自关联得到最早查询明细
                left JOIN (select * from MOBILE_DOOR_MENU_CLICK_LOG   WHERE click_time >= trunc(SYSDATE-4) and click_time <= TO_DATE(TO_CHAR(SYSDATE, 'yyyy-MM-dd HH24'),'yyyy-MM-dd HH24:MI:SS')) c
                ON c.wx_user_id = b.wx_user_id
                    AND to_CHAR(c.click_time, 'HH24:MI:SS') = b.min
                -- 根据用户名和浏览时间进行自关联得到最晚查询明细
                left JOIN (select * from MOBILE_DOOR_MENU_CLICK_LOG   WHERE click_time >= trunc(SYSDATE-4) and click_time <= TO_DATE(TO_CHAR(SYSDATE, 'yyyy-MM-dd HH24'),'yyyy-MM-dd HH24:MI:SS')) d
                ON d.wx_user_id = b.wx_user_id
                    AND to_CHAR(d.click_time, 'HH24:MI:SS') = b.max

预测

        上面的sql原则上,无论是LEFT连接还是INNER连接,都应该先执行b里面的查询,全部执行完毕之后,再执行c里面的查询,然后b表和c表进行关联。如果用的LEFT JOIN确实如此,但如果INNER JOIN就不是这样了。

执行计划

INNER JOIN

 LEFT JOIN 

         上面可以看出,INNER JOIN在执行时先执行了三个表的自关联,然后才执行第一个表的GROUP BY,因此在进行关联查询时候表的数据量是非常大的。而LEFT JOIN由于一开始就执行了GROUP BY,因此进行关联查询时数据量少了很多,所以速度非常快了。

        结论

        一般情况下,INNER JOIN 比 LEFT JOIN 返回更少的数据,因此查询效率应该更高。但是如果关联的表中有GROUP BY那么就要注意了,因为我们用()括住的sql不一定会做为一个整体去执行的,所以有时在返回的数据一样的情况下,LEFT JOIN 比 INNER JOIN 执行的是更快的,而具体什么情况下会这样,就需要我们参考两者的执行计划进行对比了,