ITPub博客

首页 > 数据库 > Oracle > 表连接方式:嵌套循环(NESTED LOOPS)

表连接方式:嵌套循环(NESTED LOOPS)

原创 Oracle 作者:a960549548 时间:2024-12-06 15:52:59 0 删除 编辑

    嵌套循环的算法:驱动表返回一行数据,通过连接列传值给被驱动表,驱动表返回多少行,被驱动表就要被扫描多少次。从下图就可以得知, nested loops有传值且必须传值的功能 (SQL语句中明明没有 DEPT表的过滤条件,但是在执行计划中却有一个等值过滤,这就是 nested loops的传值功能 )

select /*+ use_nl (e, d) full (d) e. ename, e. job, d. dname d where e. deptno=d. deptno and e. sal<11112000 Plan hash value: 1189851940 from emp Name Starts e, dept A-Time o 1 Operat ion SELECT STATEMENT NESTED LOOPS E—Rows 20 20 A—Rows 8 8 8 8 100. •00:00. 01 100. •00:00. 01 100. •00:00. 01 100. •00:00. 01 Buffers 65 65 57 Reads 12 12 TABLE ACCESS FULLI EMP TABLE ACCESS FULL I DEPT Pr dicate Information (identified by operation Id) — filter( E". " — filter( E". " " "DEPTNO")

下面根据几个实验来一起看看嵌套循环的特性与注意事项


实验一、

用scott用户下的表做测试

用了三个hint,gather_plan_statistics是为了获取A-TIME信息,use_nl是强制走NL,leading是让e强制为驱动表:

 

select /*+ gather_plan_statistics use_nl(e,d) leading(e)*/

      e.ename, e.job, d.dname

      from emp e, dept d

     where e.deptno = d.deptno;

 

执行完sql之后,select * from table(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST'));

在执行计划中,离 NESTED LOOPS 关键字最近的表就是驱动表。这里 EMP 就是驱动表, DEPT 就是被驱动表。

驱动表 EMP 扫描了一次( Id=3 , Starts=1 ),返回了 14 行数据( Id=3 , A-Row ),传值 14 次给被驱动表( Id=4 ),被驱动表扫描了 14 次( Id=4 , Id=5 , Starts=14 )。

为什么嵌套循环被驱动表的连接列要创建索引呢?因为扫描被驱动表 dept 次数为 14 次,每次需要通过 deptno 列传值,所以嵌套循环被驱动表的连接列需要创建索引。

 

实验二、

当两表使用外连接进行关联,如果执行计划是走嵌套循环,那么这时无法更改驱动表,驱动表会被固定为主表 ,例如下面 SQL 。

explain plan for select /*+ use_nl(d,e) leading(e) */  * from dept d left join emp e on d.deptno = e.deptno;

select * from table(dbms_xplan.display);

 

leading(e)表示让EMP表作为驱动表。

从执行计划中我们可以看到,DEPT与EMP是采用嵌套循环进行连接的,这说明use_nl(d,e)生效了。执行计划中驱动表为DEPT,虽然设置了leading(e),但是没有生效。

为什么leading(e)没有生效呢? 因为DEPT与EMP是外连接,DEPT是主表,EMP是从表,外连接走嵌套循环的时候驱动表只能是主表。

为什么两表关联是外连接的时候,走嵌套循环无法更改驱动表呢?

因为嵌套循环需要传值,主表传值给从表之后,如果发现从表没有关联上,直接显示为 NULL 即可;但是如果是从表传值给主表,没关联上的数据不能传值给主表,不可能传 NULL 给主表,所以两表关联是外连接的时候,走嵌套循环驱动表只能固定为主表。

 

需要注意的是, 如果外连接中 从表 有过滤条件,那么此时外连接会变为内连接, 例如下面 SQL 。

select /*+ leading(e) use_nl(d,e)*/ * from dept d left join emp e on d.deptno = e.deptno where e.sal < 3000;

        HINT 指定了让从表 EMP 作为嵌套循环驱动表,从执行计划中我们看到, EMP 确实是作为嵌套循环的驱动表,而且执行计划中没有 OUTER 关键字,这说明 SQL 已经变为内连接。

        为什么外连接的从表有过滤条件会变成内连接呢?因为 外连接的从表有过滤条件已经排除了从表与主表没有关联上显示为 NULL 的情况。


来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70013625/viewspace-3054983/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
Oracle ACE,MySQL 8.0 OCP,PMP,拥有OceanBase OBCP,TiDB PCTP,GoldenDB GDCP等多项认证,ITPUB认证专家,微信公众号:DBA之友。

注册时间:2022-02-08

  • 博文量
    132
  • 访问量
    171519