ITPub博客

首页 > 数据库 > Oracle > Oracle查询转换(五)子查询展开

Oracle查询转换(五)子查询展开

原创 Oracle 作者:stonebox1122 时间:2017-06-19 17:57:32 0 删除 编辑

子查询展开是指优化器将子查询转换为等价的表连接,从而提高查询效率。如果子查询前的where条件为:
  ● =、<、>、<=、>=、<>
  ● EXISTS、IN、ANY
  ● NOT EXISTS、NOT IN、ALL
则目标SQL就有可能会做子查询展开。

 

来看一个简单的例子:
SQL> select employee_id,last_name from employees where employee_id in (select employee_id from job_history where department_id=80);


Execution Plan
----------------------------------------------------------
Plan hash value: 2277246041

------------------------------------------------------------------------------------------------------
| Id  | Operation                      | Name                | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT               |                     |     2 |    40 |     4  (25)| 00:00:01 |
|   1 |  NESTED LOOPS                  |                     |     2 |    40 |     4  (25)| 00:00:01 |
|   2 |   NESTED LOOPS                 |                     |     2 |    40 |     4  (25)| 00:00:01 |
|   3 |    SORT UNIQUE                 |                     |     2 |    16 |     2   (0)| 00:00:01 |
|   4 |     TABLE ACCESS BY INDEX ROWID| JOB_HISTORY         |     2 |    16 |     2   (0)| 00:00:01 |
|*  5 |      INDEX RANGE SCAN          | JHIST_DEPARTMENT_IX |     2 |       |     1   (0)| 00:00:01 |
|*  6 |    INDEX UNIQUE SCAN           | EMP_EMP_ID_PK       |     1 |       |     0   (0)| 00:00:01 |
|   7 |   TABLE ACCESS BY INDEX ROWID  | EMPLOYEES           |     1 |    12 |     1   (0)| 00:00:01 |
------------------------------------------------------------------------------------------------------

 

这里的条件是IN(等价于EXISTS、=ANY),优化器是将子查询中的job_history拿出来和外部的employees表做了嵌套循环连接。可以使用NO_UNNEST Hint不让优化器做子查询展开:

 

SQL> select employee_id,last_name from employees where employee_id in (select /*+ no_unnest */employee_id from job_history where department_id=80);


Execution Plan
----------------------------------------------------------
Plan hash value: 3468528558

--------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name              | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |                   |     1 |    12 |   109   (0)| 00:00:01 |
|*  1 |  FILTER                      |                   |       |       |            |          |
|   2 |   VIEW                       | index$_join$_001  |   107 |  1284 |     2   (0)| 00:00:01 |
|*  3 |    HASH JOIN                 |                   |       |       |            |          |
|   4 |     INDEX FAST FULL SCAN     | EMP_EMP_ID_PK     |   107 |  1284 |     1   (0)| 00:00:01 |
|   5 |     INDEX FAST FULL SCAN     | EMP_NAME_IX       |   107 |  1284 |     1   (0)| 00:00:01 |
|*  6 |   TABLE ACCESS BY INDEX ROWID| JOB_HISTORY       |     1 |     8 |     2   (0)| 00:00:01 |
|*  7 |    INDEX RANGE SCAN          | JHIST_EMPLOYEE_IX |     1 |       |     1   (0)| 00:00:01 |
--------------------------------------------------------------------------------------------------

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

   1 - filter( EXISTS (SELECT /*+ NO_UNNEST */ 0 FROM "JOB_HISTORY" "JOB_HISTORY" WHERE
              "EMPLOYEE_ID"=:B1 AND "DEPARTMENT_ID"=80))

 

这个时候,子查询会在最后最后一步执行,且走filter执行计划,相当于使用子查询对主查询的结果逐一过滤,这个效率是比较低的。

如果条件是NOT IN(等价于 NOT EXISTS、<>ALL),则会转换成对应的反连接。

SQL> select employee_id,last_name from employees where employee_id not in (select employee_id from job_history where department_id=80);

106 rows selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 2462043498

----------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name                | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |                     |   105 |  2100 |     4   (0)| 00:00:01 |
|*  1 |  HASH JOIN ANTI              |                     |   105 |  2100 |     4   (0)| 00:00:01 |
|   2 |   VIEW                       | index$_join$_001    |   107 |  1284 |     2   (0)| 00:00:01 |
|*  3 |    HASH JOIN                 |                     |       |       |            |          |
|   4 |     INDEX FAST FULL SCAN     | EMP_EMP_ID_PK       |   107 |  1284 |     1   (0)| 00:00:01 |
|   5 |     INDEX FAST FULL SCAN     | EMP_NAME_IX         |   107 |  1284 |     1   (0)| 00:00:01 |
|   6 |   TABLE ACCESS BY INDEX ROWID| JOB_HISTORY         |     2 |    16 |     2   (0)| 00:00:01 |
|*  7 |    INDEX RANGE SCAN          | JHIST_DEPARTMENT_IX |     2 |       |     1   (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------

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

请登录后发表评论 登录
全部评论

注册时间:2013-12-13

  • 博文量
    204
  • 访问量
    1188944