表的三大连接之 NESTED LOOPS JOINS

-- 表的连接顺序

-- 构造数据

drop table t1 cascade constraints purge;
drop table t2 cascade constraints purge;
create table t1 (id number not null,n number, contents varchar2(4000));
create table t2 (id number not null,t1_id number not null,n number, contents varchar2(4000));
exec dbms_random.seed(0);
insert into t1 select rownum,rownum,dbms_random.string('a',50) from dual connect by level<=100 order by dbms_random.random;
insert into t2 select rownum,rownum,rownum,dbms_random.string('b',50) from dual connect by level<=100000 order by dbms_random.random;
commit;
select count(*) from t1;
select count(*) from t2;
set linesize 1000  --建议设置大一些,否则有些列显示不出来
alter session set statistics_level=all;
select /*+ leading(t1) use_nl(t2)*/ * from t1,t2 where t1.id=t2.t1_id;
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
ZBB@test>select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));

PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------
SQL_ID  8ac6hucf5k4sx, child number 0
-------------------------------------
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   | Buffers |
-------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |      1 |        |     99 |00:00:00.56 |   99516 |
|   1 |  NESTED LOOPS      |      |      1 |     99 |     99 |00:00:00.56 |   99516 |
|   2 |   TABLE ACCESS FULL| T1   |      1 |     99 |     99 |00:00:00.01 |      14 |
|*  3 |   TABLE ACCESS FULL| T2   |     99 |      1 |     99 |00:00:00.56 |   99502 |
-------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

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

Note
-----

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------
   - dynamic sampling used for this statement (level=2)

在上面的例子中,t1是驱动表,执行计划先访问t1,返回了99条数据,然后再访问T2,访问了99次。也即是说,驱动表访问了一次,被驱动表访问了99次

set linesize 1000
alter session set statistics_level=all;
select /*+ leading(t1) use_nl(t2)*/ * from t1,t2 where t1.id=t2.t1_id and t1.n in (17,19);
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
ZBB@test>select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));

PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------
SQL_ID  1xfpmcbf53k4a, child number 0
-------------------------------------
select /*+ leading(t1) use_nl(t2)*/ * from t1,t2 where t1.id=t2.t1_id
and t1.n in (17,19)

Plan hash value: 1967407726

-------------------------------------------------------------------------------------
| Id  | Operation          | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
-------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |      1 |        |      2 |00:00:00.01 |    2019 |
|   1 |  NESTED LOOPS      |      |      1 |      2 |      2 |00:00:00.01 |    2019 |
|*  2 |   TABLE ACCESS FULL| T1   |      1 |      2 |      2 |00:00:00.01 |       8 |
|*  3 |   TABLE ACCESS FULL| T2   |      2 |      1 |      2 |00:00:00.01 |    2011 |
-------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter(("T1"."N"=17 OR "T1"."N"=19))
   3 - filter("T1"."ID"="T2"."T1_ID")


PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------
Note
-----
   - dynamic sampling used for this statement (level=2)


26 rows selected.

在上面的例子中,驱动表T1访问了1次。返回2条记录,被驱动表被访问了2次。

再举个例子,有点极端

select /*+ leading(t1) use_nl(t2)*/ * from t1,t2 where t1.id=t2.t1_id and t1.n=9999999999999999;
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
ZBB@test>select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));

PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------------
SQL_ID  gr39nar9qdt2z, child number 0
-------------------------------------
select /*+ leading(t1) use_nl(t2)*/ * from t1,t2 where t1.id=t2.t1_id
and t1.n=9999999999999999

Plan hash value: 1967407726

-------------------------------------------------------------------------------------
| Id  | Operation          | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
-------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |      1 |        |      0 |00:00:00.01 |       7 |
|   1 |  NESTED LOOPS      |      |      1 |      1 |      0 |00:00:00.01 |       7 |
|*  2 |   TABLE ACCESS FULL| T1   |      1 |      1 |      0 |00:00:00.01 |       7 |
|*  3 |   TABLE ACCESS FULL| T2   |      0 |      1 |      0 |00:00:00.01 |       0 |
-------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

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


PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------
Note
-----
   - dynamic sampling used for this statement (level=2)


26 rows selected.

上面例子中,驱动表t1被访问了1次,被驱动表t2 被访问了0次 。

再举一个极端的例子

select /*+ leading(t1) use_nl(t2)*/ * from t1,t2 where t1.id=t2.t1_id and 1=2;
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
ZBB@test>select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));

PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------
SQL_ID  a2r9u1k4qkzb7, child number 0
-------------------------------------
select /*+ leading(t1) use_nl(t2)*/ * from t1,t2 where t1.id=t2.t1_id
and 1=2

Plan hash value: 521644914

----------------------------------------------------------------------------
| Id  | Operation           | Name | Starts | E-Rows | A-Rows |   A-Time   |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |      |      1 |        |      0 |00:00:00.01 |
|*  1 |  FILTER             |      |      1 |        |      0 |00:00:00.01 |
|   2 |   NESTED LOOPS      |      |      0 |     99 |      0 |00:00:00.01 |
|   3 |    TABLE ACCESS FULL| T1   |      0 |     99 |      0 |00:00:00.01 |
|*  4 |    TABLE ACCESS FULL| T2   |      0 |      1 |      0 |00:00:00.01 |
----------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter(NULL IS NOT NULL)
   4 - filter("T1"."ID"="T2"."T1_ID")

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------

Note
-----
   - dynamic sampling used for this statement (level=2)


27 rows selected.
从上面的例子,and条件1=2 根本就不会成立。所以t1根本无须访问, 直接通过访问数据字典,获取到两个表的结构就好了 。


结论-
nested loops join中,驱动表被访问0或者1次,被驱动表被访问0次或者N次,N由于、驱动表返回的结果集的条数决定。


END.




猜你喜欢

转载自blog.csdn.net/xxzhaobb/article/details/80909664
今日推荐