oracle表连接之----〉嵌套循环(Nested Loops Join)

嵌套循环连接(Nested Loops Join)是一种两个表在做表连接时依靠两层嵌套循环(分别为外层循环和内存循环)来得到连接结果集的表连接方法。即外层循环对应的驱动结果集有多少条记录,遍历被驱动表的内层循环就要做多少次,这就是所谓的“嵌套循环”的含义。

对于嵌套循环连接的优缺点及适用场景如下:

a,如果驱动表所对应的驱动结果集的记录数较少,同时在被驱动表的连接列上又存在唯一性索引(或者在被驱动表的连接列上存在选择性好的非唯一性索引),那么此时使用嵌套循环连接的执行效率就会非常高;但如果驱动表所对应的驱动结果集的记录数很多,即便在被驱动表的连接列上存在索引,此时使用嵌套循环连接的执行效率也不会很高。

b,大表也可以作为嵌套循环连接的驱动表,关键是看目标SQL中指定的谓词条件(如果有的话)能否将驱动结果集的记录集数量大幅度的降下来。

c,嵌套循环连接有其他连接方法所没有的一个优点:嵌套循环连接可以实现快速响应。因为排序合并连接需要等到排序完后做合并操作时才能开始返回数据,而哈希连接则也等到驱动结果集所对应的HASH TABLE全部构建完后才能开始返回数据。

oracle表之间的连接之嵌套循环连接(Nested Loops Join),其特点如下:

1,驱动表返回几天记录,被驱动表就被访问多少次。

2,嵌套循环表连接的表有驱动顺序。

3,嵌套循环表连接的表无需要排序。

4,嵌套循环表连接的表没有任何限制场景,即任何SQL语句都可以用嵌套循环表连接的表都可以用嵌套循环连接进行操作数据库。

5,其SQL语句的优化原则是:驱动表的限制条件的字段上需要有索引,被驱动表的连接条件的字段上需要有索引。

下面我来做个实验来证实如上的结论:

<-----------------------下面是实验的基础数据------------------------------------------------------->

drop table T1 cascade constraints purge;

CREATE TABLE T1(id number not null,num number,information VARCHAR2(4000));

drop table T2 cascade constraints purge;

CREATE TABLE T2(id number not null,T1_ID number not null, num number,information VARCHAR2(4000));

SQL> execute dbms_random.seed(0);

PL/SQL procedure successfully completed

 

SQL> insert into T1 select rownum,rownum, dbms_random.string(‘X‘,100) from dual

2  connect by level<=100 order by dbms_random.random;

100 rows inserted

SQL>

SQL> insert into T2 select rownum,rownum,rownum, dbms_random.string(‘Y‘,100) from dual

2  connect by level<=100000 order by dbms_random.random;

100000 rows inserted

SQL> COMMIT;

Commit complete

SQL> select count(*) from T1;

COUNT(*)

----------

100

SQL> select count(*) from T2;

COUNT(*)

----------

100000

<-----------------------上面是实验的基础数据----end --------------------------------------------------->

下面测试表的访问次数:

Nested Loops Join,T2表被访问100次

SQL> set linesize 1000;

SQL> alter session set statistics_level=all;

Session altered

SQL> select /*+ leading(T1) use_nl(T2)*/ * from T1,T2 where T1.ID=T2.T1_ID;

--此处省略记录结果

SQL> select sql_id, child_number, sql_text from v$sql where sql_text like ‘%leading(t1)%‘;

SQL_ID        CHILD_NUMBER SQL_TEXT

------------- ------------ --------------------------------------------------------------------------------

901dhc61y4u01            0  select sql_id, child_number, sql_text from v$sql where sql_text like ‘%leading(

901dhc61y4u01            1  select sql_id, child_number, sql_text from v$sql where sql_text like ‘%leading(

ggu0wqwqzpw8d            0  explain plan for select /*+leading(t1) use_nl(t2)*/ * from t1,t2 where t1.id=t2

8v44uh08hk303            0  select /*+leading(t1) use_nl(t2)*/ * from t1,t2 where t1.id=t2.t1_id

8v44uh08hk303            1  select /*+leading(t1) use_nl(t2)*/ * from t1,t2 where t1.id=t2.t1_id

SQL> select * from table(dbms_xplan.display_cursor(‘8v44uh08hk303‘,1,‘allstats last‘));

PLAN_TABLE_OUTPUT

--------------------------------------------------------------------------------

SQL_ID  8v44uh08hk303, child number 1

-------------------------------------

select /*+leading(t1) use_nl(t2)*/ * from t1,t2 where t1.id=t2.t1_id

Plan hash value: 1967407726

--------------------------------------------------------------------------------

| Id  | Operation                           | Name            |
Starts     | E-Rows | A-Rows |   A-Time   | Buff

--------------------------------------------------------------------------------

|   1 |  NESTED LOOPS            |                         |      1          |    100       |    100 |00:00:00.60 |

|   2 |   TABLE ACCESS FULL | T1                    |      1           |    100      |    100 |00:00:00.01 |

|*  3 |   TABLE ACCESS FULL| T2                    |    100         |      1         |    100 |00:00:00.60 |

--------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

3 - filter("T1"."ID"="T2"."T1_ID")

Note

PLAN_TABLE_OUTPUT

--------------------------------------------------------------------------------

-----

- dynamic sampling used for this statement

23 rows selected

Note:E-ROWS表示优化器评估的行数(Evaluation Rows),A-ROWS表示实际的行数(Aactual Rows)。

从上面的执行计划可以看出,T1表被执行了一次(Starts这一列表示表被访问的次数),T2表被访问了100次!

Nested Loops Join,T2表被访问2次

SQL> select /*+leading(t1) use_nl(t2)*/ * from t1,t2 where t1.id=t2.t1_id and t1.num in(20,30);

ID        NUM INFORMATION                                                                              ID      T1_ID        NUM INFORMATION

---------- ---------- -------------------------------------------------------------------------------- ---------- ---------- ---------- --------------------------------------------------------------------------------

20         20 TDX8UJ2WUQIUUWSN9BZ3HEAKWFHENQC57VZ6PZU3L6RZ4120DO48OQ1QSEMH9E22MH0KVMQUHR2LGDLA         20         20         20 TIUTKBCQDOTYVDYYPBTPGTMPSIDWJPGTSXJUBQOWFWGMZEBQRXABOXOLQYPURIJVMCTWTNUUYZCFXOFK

30         30 0IU7YCLXJQ93Q3B6FPTS07W1T53OFF0YZH9FVYFG67WCZIIS6GEH65ITOXWDRLVJ7IJM1QMLXP40PETZ         30         30         30 JZNXYHPTRYYIDXUAGKPUCSBXIDOFSYTGUIPJRYPGFXZDHMSTPSXWFUPRCCCQFIZMGNRUVJGMHPXKEUQY

SQL> select sql_id, child_number, sql_text from v$sql where sql_text like ‘%t1.num in(20,30)%‘;

SQL_ID        CHILD_NUMBER SQL_TEXT

------------- ------------ --------------------------------------------------------------------------------

btydr0p4zft1m            0  select sql_id, child_number, sql_text from v$sql where sql_text like ‘%t1.num i

atcnxaa1ffvjd            0  select /*+leading(t1) use_nl(t2)*/ * from t1,t2 where t1.id=t2.t1_id and t1.num

SQL> select * from table(dbms_xplan.display_cursor(‘atcnxaa1ffvjd‘,0,‘allstats last‘));

PLAN_TABLE_OUTPUT

--------------------------------------------------------------------------------

SQL_ID  atcnxaa1ffvjd, child number 0

-------------------------------------

select /*+leading(t1) use_nl(t2)*/ * from t1,t2 where t1.id=t2.t1_id and

t1.num in(20,30)

Plan hash value: 1967407726

--------------------------------------------------------------------------------

| Id  | Operation          | Name | Starts
| E-Rows | A-Rows |   A-Time   | Buff

--------------------------------------------------------------------------------

|   1 |  NESTED LOOPS      |      |      1 |      2 |      2 |00:00:00.01 |    3

|*  2 |   TABLE ACCESS FULL| T1   |      1 |      2 |      2 |00:00:00.01 |

|*  3 |   TABLE ACCESS FULL| T2   |      2 |      1 |      2 |00:00:00.01 |    3

--------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

2 - filter(("T1"."NUM"=20 OR "T1"."NUM"=30))

3 - filter("T1"."ID"="T2"."T1_ID")

PLAN_TABLE_OUTPUT

--------------------------------------------------------------------------------

Note

-----

- dynamic sampling used for this statement

25 rows selected

从上面的执行计划可以看出,T1表被执行了一次(Starts这一列表示表被访问的次数),T2表被访问了2次!

Nested Loops Join,T2表被访问1次

SQL> select /*+leading(t1) use_nl(t2)*/ * from t1,t2 where t1.id=t2.t1_id and t1.num=20;

ID        NUM INFORMATION                                                                              ID      T1_ID        NUM INFORMATION

---------- ---------- -------------------------------------------------------------------------------- ---------- ---------- ---------- --------------------------------------------------------------------------------

20         20 TDX8UJ2WUQIUUWSN9BZ3HEAKWFHENQC57VZ6PZU3L6RZ4120DO48OQ1QSEMH9E22MH0KVMQUHR2LGDLA         20         20         20 TIUTKBCQDOTYVDYYPBTPGTMPSIDWJPGTSXJUBQOWFWGMZEBQRXABOXOLQYPURIJVMCTWTNUUYZCFXOFK

SQL> select sql_id, child_number, sql_text from v$sql where sql_text like ‘%t1.num=20%‘;

SQL_ID        CHILD_NUMBER SQL_TEXT

------------- ------------ --------------------------------------------------------------------------------

471w5yr5rack1            0  select sql_id, child_number, sql_text from v$sql where sql_text like ‘%t1.num=2

5jdf02xk6rj0x            0  select /*+leading(t1) use_nl(t2)*/ * from t1,t2 where t1.id=t2.t1_id and t1.num

SQL> select * from table(dbms_xplan.display_cursor(‘5jdf02xk6rj0x‘,0,‘allstats last‘));

PLAN_TABLE_OUTPUT

--------------------------------------------------------------------------------

SQL_ID  5jdf02xk6rj0x, child number 0

-------------------------------------

select /*+leading(t1) use_nl(t2)*/ * from t1,t2 where t1.id=t2.t1_id and

t1.num=20

Plan hash value: 1967407726

--------------------------------------------------------------------------------

| Id  | Operation          | Name | Starts| E-Rows | A-Rows |   A-Time   | Buff

--------------------------------------------------------------------------------

|   1 |  NESTED LOOPS      |      |      1 |      1 |      1 |00:00:00.01 |    1

|*  2 |   TABLE ACCESS FULL| T1   |      1 |      1 |      1 |00:00:00.01 |

|*  3 |   TABLE ACCESS FULL| T2   |      1 |      1 |      1 |00:00:00.01 |    1

--------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

2 - filter("T1"."NUM"=20)

3 - filter("T1"."ID"="T2"."T1_ID")

PLAN_TABLE_OUTPUT

--------------------------------------------------------------------------------

Note

-----

- dynamic sampling used for this statement

25 rows selected

从上面的执行计划可以看出,T1表被执行了一次(Starts这一列表示表被访问的次数),T2表被访问了1次!

Nested Loops Join,T2表被访问0次

SQL> select /*+leading(t1) use_nl(t2)*/ * from t1,t2 where t1.id=t2.t1_id and t1.num=888888888;

ID        NUM INFORMATION                                                                              ID      T1_ID        NUM INFORMATION

---------- ---------- -------------------------------------------------------------------------------- ---------- ---------- ---------- --------------------------------------------------------------------------------

SQL> select sql_id, child_number, sql_text from v$sql where sql_text like ‘%t1.num=8888888%‘;

SQL_ID        CHILD_NUMBER SQL_TEXT

------------- ------------ --------------------------------------------------------------------------------

6z2jrdf4snd59            0  select /*+leading(t1) use_nl(t2)*/ * from t1,t2 where t1.id=t2.t1_id and t1.num

1h86xkxg3psb6            0  select sql_id, child_number, sql_text from v$sql where sql_text like ‘%t1.num=8

SQL> select * from table(dbms_xplan.display_cursor(‘6z2jrdf4snd59‘,0,‘allstats last‘));

PLAN_TABLE_OUTPUT

--------------------------------------------------------------------------------

SQL_ID  6z2jrdf4snd59, child number 0

-------------------------------------

select /*+leading(t1) use_nl(t2)*/ * from t1,t2 where t1.id=t2.t1_id and

t1.num=888888888

Plan hash value: 1967407726

--------------------------------------------------------------------------------

| Id  | Operation          | Name | Starts | E-Rows | A-Rows |   A-Time   | Buff

--------------------------------------------------------------------------------

|   1 |  NESTED LOOPS      |      |      1 |      1 |      0 |00:00:00.01 |

|*  2 |   TABLE ACCESS FULL| T1   |      1 |      1 |      0 |00:00:00.01 |

|*  3 |   TABLE ACCESS FULL| T2   |      0 |      1 |      0 |00:00:00.01 |

--------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

2 - filter("T1"."NUM"=888888888)

3 - filter("T1"."ID"="T2"."T1_ID")

PLAN_TABLE_OUTPUT

--------------------------------------------------------------------------------

Note

-----

- dynamic sampling used for this statement

25 rows selected

从上面的执行计划可以看出,T1表被执行了一次(Starts这一列表示表被访问的次数),T2表被访问了0次!

通过上面的实验可以得出如下的结论:

T1表的查询返回多少条记录,T2 表就被访问多少次。第一次T1表返回100条记录,是因为T1表全表就是100条记录,无条件查询T1表,所以T1表的100条记录都返回了;而第二次的限制条件and t1.num in (20,30)的条件让T1只返回2条记录,所以T2被访问2次;第三次t1.num=20的条件让T1表只返回1条记录,所以T2只查询一次;最后一次and t1.num=88888888这个条件从T1中找不到记录,所以T2表就干脆不访问了。

下面来证明下上面T1表的返回记录数:

说明T2表为什么被访问100次。

SQL> select count(*) from t1;

COUNT(*)

----------

100

说明T2表为什么被访问2次。

SQL> select count(*) from t1 where t1.num in (20,30);

COUNT(*)

----------

2

说明T2表为什么被访问1次。

SQL> select count(*) from t1 where t1.num=20;

COUNT(*)

----------

1

说明T2表为什么被访问0次。

SQL> select count(*) from t1 where t1.num=888888888;

COUNT(*)

----------

0

上面我使用的/*+ leading(t1) use_nl(t2)*/这个HINT的含义,USE_NL表示强制ORACLE的优化器使用嵌套循环的链接方式,leading(t1)表示T1作为驱动表。

通过上面的实验可以这个结论:在嵌套循环连接中,驱动表返回多少条记录,被驱动表就被访问多少次!!!

oracle表连接之----〉嵌套循环(Nested Loops Join),布布扣,bubuko.com

时间: 2024-10-29 19:08:14

oracle表连接之----〉嵌套循环(Nested Loops Join)的相关文章

SQL Tuning 基础概述06 - 表的连接方式:Nested Loops Join,Merge Sort Join &amp; Hash Join

nested loops join 嵌套循环 merge sort join 排序合并 hash join 哈希连接 nested loops join(嵌套循环)   驱动表返回几条结果集,被驱动表访问多少次,有驱动顺序,无须排序,无任何限制. 驱动表限制条件有索引,被驱动表连接条件有索引. hints:use_nl() merge sort join(排序合并)   驱动表和被驱动表都是最多访问1次,无驱动顺序,需要排序(SORT_AREA_SIZE),连接条件是<>或like导致无法使用

oracle表连接

oracle表连接又被问到了,感觉细节了解还是远远不够啊,从网上找资料学习之.转载的. 在查看sql执行计划时,我们会发现表的连接方式有多种,本文对表的连接方式进行介绍以便更好看懂执行计划和理解sql执行原理. 一.连接方式:         嵌套循环(Nested  Loops (NL))       (散列)哈希连接(Hash Join (HJ))     (归并)排序合并连接(Sort Merge Join (SMJ) ) 二.连接说明:     1.Oracle一次只能连接两个表.不管查

oracle 表连接 - nested loop 嵌套循环连接

一. nested loop 原理 nested loop 连接(循环嵌套连接)指的是两个表连接时, 通过两层嵌套循环来进行依次的匹配, 最后得到返回结果集的表连接方法. 假如下面的 sql 语句中表 T1 和 T2 的连接方式是循环嵌套连接, T1 是驱动表 select * from T1, T2 where T1.id = T2.id and T1.name = 'David'; 那么将上述 sql 语句翻译为伪码应该如下所示:. for each row in (select * fro

oracle 表连接 - hash join 哈希连接

一. hash 连接(哈希连接)原理 指的是两个表连接时, 先利用两表中记录较少的表在内存中建立 hash 表, 然后扫描记录较多的表并探測 hash 表, 找出与 hash 表相匹配的行来得到结果集的表连接方法. 哈希连接仅仅能用于等值连接条件(=). 如果以下的 sql 语句中表 T1 和 T2 的连接方式是哈希连接, T1 是驱动表 select * from T1, T2 where T1.id = T2.id and T1.name = 'David'; oracle 运行过程例如以下

Oracle 表连接方式

1.嵌套循环联结(NESTED LOOPS)2.哈希联结(HASH JOIN)3.排序合并联结(MERGE JOIN)4.半联结(in/exists)5.反联结(not in/not exists)6.笛卡儿联结(MERGE JOIN CARTESIAN)7.外连联结    left outer join    right outer join    full outer join8.索引联结 左外连接:以左边的表为基准,右边连接的表没有返回值时为空. 右外连接:以右边的表为基准,左边连接的表没

oracle 表连接 - sort merge joins 排序合并连接

一. sort merge joins连接(排序合并连接) 原理 指的是两个表连接时, 通过连接列先分别排序后, 再通过合并操作来得到最后返回的结果集的方法. 假如表 T1 和 T2 的连接方式是排序合并连接, oracle 执行步骤如下: (1) 根据 sql 语句中的谓词条件(如果有) 访问 T1 表, 得到一个过滤的结果集, 然后按照 T1 中的连接列对结果集进行排序 (2) 根据 sql 语句中的谓词条件(如果有) 访问 T2 表, 得到一个过滤的结果集, 然后按照 T2 中的连接列对结

深入理解Oracle表(5):三大表连接方式详解之Hash Join的定义,原理,算法,成本,模式和位图...

Hash Join只能用于相等连接,且只能在CBO优化器模式下.相对于nested loop join,hash join更适合处理大型结果集       Hash Join的执行计划第1个是hash表(build table),第2个探查表(probe table),一般不叫内外表,nested loop才有内外表       Hash表也就是所谓的内表,探查表所谓的外表       两者的执行计划形如:       nested loop           outer table    

Oracle表连接总结

1 简述 1) 两个表的连接,是通过将一个表中的一列或者多列同另一个表中的列链接而建立起来的.用来连接两张表的表达式组成了连接条件.当连接成功后,第二张表中的数据就同第一张表连接起来了,并形成了复合结果集 2) 有5种基本类型的的连接,内连接,外连接,自然连接,交叉连接,自连接.下面分别说下撒. 2 内连接(Inner Join / Join) Inner join逻辑运算符返回满足第一个(顶端)输入与第二个(底端)输入联接的每一行.这个和用select查询多表是一样的效果,所以内连接用的很少.

Oracle 表连接方式(1)---

Oracle 表之间的连接分为三种: 1. 内连接(自然连接) 2. 外连接 (1)左外连接 (左边的表不加限制) (2)右外连接(右边的表不加限制) (3)全外连接(左右两表都不加限制) 3. 自连接(同一张表内的连接) SQL的标准语法: select table1.column,table2.column from table1 [inner | left | right | full ] join table2 on table1.column1 = table2.column2; in