orale里的反连接

反连接:是指两个数据集之间的一种特殊连接类型,驱动数据集中最终返回的数据是丢弃匹配被驱动集记录后剩余的记录。

这里总结几点使用反连接的必要条件。
1、语句在NOT IN(!=ALL)或NOT EXISTS子句中有一个子查询。
2、使用NOT EXISTS语法时为了使得到的结果有意义,要使用相关的子查询。
3、NOT IN和NOT EXISTS字句不能包含于OR分支中。

注:这里的代码清单里所涉及的表来自HR Sample Schema。

代码清单1-1 使用NOT IN和NOT EXISTS

  1. select department_name
  2. from DEPARTMENTS
  3. where DEPARTMENT_ID not in (select DEPARTMENT_ID from EMPLOYEES);

  4. no rows selected

Execution Plan
----------------------------------------------------------
Plan hash value: 4201340344
---------------------------------------------------------------------------------------------
| Id  | Operation                     | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |             |    17 |   323 |     6  (17)| 00:00:01 |
|   1 |  MERGE JOIN ANTI NA           |             |    17 |   323 |     6  (17)| 00:00:01 |
|   2 |   SORT JOIN                   |             |    27 |   432 |     2   (0)| 00:00:01 |
|   3 |    TABLE ACCESS BY INDEX ROWID| DEPARTMENTS |    27 |   432 |     2   (0)| 00:00:01 |
|   4 |     INDEX FULL SCAN           | DEPT_ID_PK  |    27 |       |     1   (0)| 00:00:01 |
|*  5 |   SORT UNIQUE                 |             |   107 |   321 |     4  (25)| 00:00:01 |
|   6 |    TABLE ACCESS FULL          | EMPLOYEES   |   107 |   321 |     3   (0)| 00:00:01 |
---------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   5 - access("DEPARTMENT_ID"="DEPARTMENT_ID")
       filter("DEPARTMENT_ID"="DEPARTMENT_ID")

  1. SELECT department_name FROM departments
  2. WHERE NOT EXISTS
  3. (SELECT null FROM employees
  4. WHERE departments.department_id = employees.department_id);

  5. DEPARTMENT_NAME
  6. ------------------------------
  7. Treasury
  8. Corporate Tax
  9. Control And Credit
  10. Shareholder Services
  11. Benefits
  12. Manufacturing
  13. Construction
  14. Contracting
  15. Operations
  16. IT Support
  17. NOC
  18. IT Helpdesk
  19. Government Sales
  20. Retail Sales
  21. Recruiting
  22. Payroll
  23. 16 rows selected.

Execution Plan
----------------------------------------------------------
Plan hash value: 3082375452
----------------------------------------------------------------------------------------
| Id  | Operation          | Name              | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |                   |    17 |   323 |     3   (0)| 00:00:01 |
|   1 |  NESTED LOOPS ANTI |                   |    17 |   323 |     3   (0)| 00:00:01 |
|   2 |   TABLE ACCESS FULL| DEPARTMENTS       |    27 |   432 |     3   (0)| 00:00:01 |
|*  3 |   INDEX RANGE SCAN | EMP_DEPARTMENT_IX |    41 |   123 |     0   (0)| 00:00:01 |
----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   3 - access("DEPARTMENTS"."DEPARTMENT_ID"="EMPLOYEES"."DEPARTMENT_ID")
==>上述代码中not in和not exists并没有返回相同值。这是因为not in是关心空值的,如果not in运算符返回了一个空值,
   则整个查询不会返回任何记录。not exists则不关心空值。这里有2点需要说明下:
   1、not in代码执行计划步骤2中出现了关键字‘ MERGE JOIN ANTI NA ’,ANTI表示使用了反连接,ANTI NA表示使用考虑空值的反连接。
   11g以前,除非确定not in运算符不会返回空值,否则不能在not in查询中使用反连接。
   2、为了使not in忽略空值的影响,可以有以下选择:

        查询列上使用nvl函数
        查询列上实现not null约束
         子查询中加上is not null谓语
         使用not exists代替not in

代码清单1-2  使用or分支禁用反连接    

  1. select department_name
  2. from DEPARTMENTS
  3. where 1=2 or DEPARTMENT_ID not in (select DEPARTMENT_ID from EMPLOYEES where DEPARTMENT_ID is not null);
  4. DEPARTMENT_NAME
  5. ------------------------------
  6. Treasury
  7. Corporate Tax
  8. Control And Credit
  9. Shareholder Services
  10. Benefits
  11. Manufacturing
  12. Construction
  13. Contracting
  14. Operations
  15. IT Support
  16. NOC
  17. IT Helpdesk
  18. Government Sales
  19. Retail Sales
  20. Recruiting
  21. Payroll
  22. 16 rows selected.

Execution Plan
----------------------------------------------------------
Plan hash value: 440241596
----------------------------------------------------------------------------------------
| Id  | Operation          | Name              | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |                   |    27 |   432 |     4   (0)| 00:00:01 |
|*  1 |  FILTER            |                   |       |       |            |          |
|   2 |   TABLE ACCESS FULL| DEPARTMENTS       |    27 |   432 |     3   (0)| 00:00:01 |
|*  3 |   INDEX RANGE SCAN | EMP_DEPARTMENT_IX |     2 |     6 |     1   (0)| 00:00:01 |
----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter( NOT EXISTS (SELECT 0 FROM "EMPLOYEES" "EMPLOYEES" WHERE
              "DEPARTMENT_ID"=:B1 AND "DEPARTMENT_ID" IS NOT NULL))
   3 - access("DEPARTMENT_ID"=:B1)
       filter("DEPARTMENT_ID" IS NOT NULL)

  1. SELECT department_name FROM departments
  2. WHERE NOT EXISTS
  3. (SELECT null FROM employees
  4. WHERE 1=2 or departments.department_id = employees.department_id);
  5. DEPARTMENT_NAME
  6. ------------------------------
  7. Treasury
  8. Corporate Tax
  9. Control And Credit
  10. Shareholder Services
  11. Benefits
  12. Manufacturing
  13. Construction
  14. Contracting
  15. Operations
  16. IT Support
  17. NOC
  18. IT Helpdesk
  19. Government Sales
  20. Retail Sales
  21. Recruiting
  22. Payroll
  23. 16 rows selected.

Execution Plan
----------------------------------------------------------
Plan hash value: 440241596
----------------------------------------------------------------------------------------
| Id  | Operation          | Name              | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |                   |    26 |   416 |    17   (0)| 00:00:01 |
|*  1 |  FILTER            |                   |       |       |            |          |
|   2 |   TABLE ACCESS FULL| DEPARTMENTS       |    27 |   432 |     3   (0)| 00:00:01 |
|*  3 |   INDEX RANGE SCAN | EMP_DEPARTMENT_IX |     2 |     6 |     1   (0)| 00:00:01 |
----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter( NOT EXISTS (SELECT 0 FROM "EMPLOYEES" "EMPLOYEES" WHERE
              "EMPLOYEES"."DEPARTMENT_ID"=:B1))
   3 - access("EMPLOYEES"."DEPARTMENT_ID"=:B1)
==>上述代码中在or字句中使用了not in和not exists,执行计划中都未使用反连接。

最后介绍下如何控制反连接执行计划
1、使用提示(hint)
ANTIJOIN-进行反连接

2、通过隐含参数
_always_anti_join 默认值为CHOOSE,允许优化器选择最高效的执行方法。将值设置为OFF则禁用了反连接,可在实例级别设定该参数。
_optimizer_null_aware_antijoin 默认值为TRUE,表示优化器会采用能够处理NULL值的反连接(即执行计划中出现‘ANTI NA')。

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

转载于:http://blog.itpub.net/25923810/viewspace-2130979/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值