当前位置:数据库 > Oracle >>

oracle半连接(in,exists)相关参数

oracle半连接(in,exists)相关参数
 
半连接和反连接,其实就是in,exists,之前我对这几个玩意其实也很迷茫,看网上都有的说exists比in好,等等之类的,其实并不然,等了解了他的一些内部机制,就不会再这么盲目了。
        那么我先看几个相关参数:
_always_semi_join=CHOOSE  这个说明是按最小成本选择半连接
这个参数可以通过select NAME_KSPVLD_VALUES name, VALUE_KSPVLD_VALUES value
from X$KSPVLD_VALUES
where NAME_KSPVLD_VALUES like nvl('&name',NAME_KSPVLD_VALUES);
Enter value for name: _always_semi_join来查看都有那些值。
HASH JOIN SEMI 也叫哈希半连接
做个实验:
create table filter (易做图 varchar2(2));
insert into filter values ('男');
insert into filter values ('女');
insert into filter values ('男');
insert into filter values ('男');
insert into filter values ('女');
commit;
create table emp1(emp_no number,易做图 varchar2(2));
insert into emp1 select rownum ,易做图 from filter order by 2;
insert into emp1 select rownum ,易做图 from filter order by 2;
commit;
execute dbms_stats.gather_table_stats(ownname=>user, tabname=>'FILTER')
execute dbms_stats.gather_table_stats(ownname=>user, tabname=>'EMP1')
首先测试HASH半连接:
首先hash半连接_always_semi_join=CHOOSE  这个参数一定是choose,也就是根据最小成本选择半连接。
SELECT /*+ gather_plan_statistics */ * FROM EMP1 WHERE EXISTS
(SELECT  0 FROM FILTER
WHERE FILTER.SEX=EMP1.SEX);
SELECT * FROM table(dbms_xplan.display_cursor(null,null,'iostats last'));
看结果:
 
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  bkvqwm45n1fdb, child number 0
-------------------------------------
SELECT /*+ gather_plan_statistics */ * FROM EMP1 WHERE EXISTS (SELECT  0 FROM
FILTER WHERE FILTER.SEX=EMP1.SEX)
Plan hash value: 1392637843
---------------------------------------------------------------------------------------
| Id  | Operation          | Name   | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
---------------------------------------------------------------------------------------
|*  1 |  HASH JOIN SEMI    |        |      1 |     10 |     10 |00:00:00.01 |      14 |
|   2 |   TABLE ACCESS FULL| EMP1   |      1 |     10 |     10 |00:00:00.01 |       7 |
|   3 |   TABLE ACCESS FULL| FILTER |      1 |      5 |      2 |00:00:00.01 |       7 |
---------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - access("FILTER"."SEX"="EMP1"."SEX")
好,来解释一下这个执行计划,现在可以看到1是hash 半连接,首先扫描emp1表,再扫描filter表,emp1这里是驱动表,取出10行,生成hash表,每取出一行就去另一个hash表filter表过滤一下,emp1性别2种,所以一种性别去过滤一次就结束,不用再往下匹配,这里也就是'男'匹配一次,'女'匹配一次,总共两次。上面A-Rows为2,说明这个表过滤作用的就两个值,有几个值就有几个A-Rows.
上面是用exists,下面用in看一下:
SELECT /*+ gather_plan_statistics  */ * FROM EMP1 WHERE 易做图 in  
   (SELECT /*+ USE_HASH  */ 易做图 FROM FILTER);
结果和上面的执行计划是一样的。这里in和exists就是一样的,都是hash半连接。
下面看一下不用hash半连接的:
alter session set "_always_semi_join" = OFF;
SELECT /*+ gather_plan_statistics  */ * FROM EMP1 WHERE 易做图 in  
 (SELECT /*+ USE_HASH  */ 易做图 FROM FILTER);
SELECT * FROM table(dbms_xplan.display_cursor(null,null,'iostats last'));
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  1p9a7sq3tdb4p, child number 0
-------------------------------------
SELECT /*+ gather_plan_statistics  */ * FROM EMP1 WHERE 易做图 in  (SELECT /*+
USE_HASH  */ 易做图 FROM FILTER)
Plan hash value: 3840124480
---------------------------------------------------------------------------------------
| Id  | Operation          | Name   | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
---------------------------------------------------------------------------------------
|*  1 |  FILTER            |        |      1 |        |     10 |00:00:00.01 |      20 |
|   2 |   TABLE ACCESS FULL| EMP1   |      1 |     10 |     10 |00:00:00.01 |       8 |
|*  3 |   TABLE ACCESS FULL| FILTER |      2 |      1 |      2 |00:00:00.01 |      12 |
---------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter( IS NOT NULL)
   3 - filter("SEX"=:B1)
这里可以看到用的filter,性能比半连接的性能还好。
嵌套半连接:
alter session set "_always_semi_join" = 'CHOOSE';先修改回来
SELECT /*+ gather_plan_statistics */ * FROM EMP1 WHERE EXISTS
(SELECT /*+ NL_SJ */ 0 FROM FILTER
WHERE FILTER.SEX=EMP1.SEX);
SELECT * FROM table(dbms_xplan.display_cursor(null,null,'iostats last'));
Plan hash value: 2921932404
---------------------------------------------------------------------------------------
| Id  | Operation          | Name   | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
---------------------------------------------------------------------------------------
|   1 |  NESTED LOOPS SEMI |        |      1 |     10 |     10 |00:00:00.01 |      20 |
|   2 |   TABLE ACCESS FULL| EMP1   |      1 |     10 |     10 |00:00:00.01 |       8 |
|*  3 |   TABLE ACCESS FULL| FILTER |      2 |      5 |      2 |00:00:00.01 |      12 |
---------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   3 - filter("FILTER"."SEX"="EMP1"."SEX")
NL_SJ需要放到IN子句,或者EXISTS和NOT EXISTS语句中,是强制走嵌套半连接的意思,这里看到1就
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,