1.限制子查询展开情况(rownum或者Row_Number() Over 函数):
SQL>select ename, deptno
from emp
where deptno in (select
deptno
from dept
where dname = 'SALES' ); 2 3 4 5 6
6 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 844388907
----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 5 | 165 | 6 (17)| 00:00:01 |
| 1 | MERGE JOIN | | 5 | 165 | 6 (17)| 00:00:01 |
|* 2 | TABLE ACCESS BY INDEX ROWID| DEPT | 1 | 13 | 2 (0)| 00:00:01 |
| 3 | INDEX FULL SCAN | PK_DEPT | 4 | | 1 (0)| 00:00:01 |
|* 4 | SORT JOIN | | 14 | 280 | 4 (25)| 00:00:01 |
| 5 | TABLE ACCESS FULL | EMP | 14 | 280 | 3 (0)| 00:00:01 |
----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("DNAME"='SALES')
4 - access("DEPTNO"="DEPTNO")
filter("DEPTNO"="DEPTNO")
SQL> select ename, deptno
from emp
where deptno in (select
deptno
from dept
where dname = 'SALES' and rownum<2); 2 3 4 5 6
6 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 1827978183
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 5 | 100 | 6 (0)| 00:00:01 |
|* 1 | FILTER | | | | | |
| 2 | TABLE ACCESS FULL | EMP | 15 | 300 | 3 (0)| 00:00:01 |
|* 3 | FILTER | | | | | |
|* 4 | COUNT STOPKEY | | | | | |
|* 5 | TABLE ACCESS FULL| DEPT | 1 | 22 | 3 (0)| 00:00:01 |
-----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter( EXISTS (<not feasible>)
3 - filter("DEPTNO"=:B1)
4 - filter(ROWNUM<2)
5 - filter("DNAME"='SALES')
可以看到ROWNUM会影响子查询展开
2. union unionall 会限制 子查询 展开
SQL> select ename, deptno
from emp
where deptno in (select
deptno
from dept
where dname = 'SALES' union select deptno from dept where dname ='OPERATIONS' ); 2 3 4 5 6
6 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 2859252660
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 10 | 200 | 11 (19)| 00:00:01 |
|* 1 | FILTER | | | | | |
| 2 | TABLE ACCESS FULL | EMP | 15 | 300 | 3 (0)| 00:00:01 |
| 3 | SORT UNIQUE | | 2 | 44 | 8 (63)| 00:00:01 |
| 4 | UNION-ALL | | | | | |
|* 5 | TABLE ACCESS FULL| DEPT | 1 | 22 | 3 (0)| 00:00:01 |
|* 6 | TABLE ACCESS FULL| DEPT | 1 | 22 | 3 (0)| 00:00:01 |
-----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter( EXISTS ( (SELECT "DEPTNO" FROM "DEPT" "DEPT" WHERE
"DEPTNO"=:B1 AND "DNAME"='SALES')UNION (SELECT "DEPTNO" FROM "DEPT"
"DEPT" WHERE "DEPTNO"=:B2 AND "DNAME"='OPERATIONS')))
5 - filter("DEPTNO"=:B1 AND "DNAME"='SALES')
6 - filter("DEPTNO"=:B1 AND "DNAME"='OPERATIONS')
3.子查询外面使用的是exists,CBO里面有个限制:当子查询里面有 start with....connect by , CBO不会对子查询进行转换
如果子查询外面是In就可以展开
SQL> select *
from departments a
where exists
(SELECT 1
FROM employees b
START WITH employee_id = 101
CONNECT BY PRIOR employee_id = manager_id
and a.department_id=b.department_id);
2 3 4 5 6 7 8
27 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 3077864849
------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 21 | 44 (0)| 00:00:01 |
|* 1 | FILTER | | | | | |
| 2 | TABLE ACCESS FULL | DEPARTMENTS | 27 | 567 | 3 (0)| 00:00:01 |
|* 3 | CONNECT BY WITH FILTERING (UNIQUE)| | | | | |
| 4 | TABLE ACCESS BY INDEX ROWID | EMPLOYEES | 1 | 11 | 1 (0)| 00:00:01 |
|* 5 | INDEX UNIQUE SCAN | EMP_EMP_ID_PK | 1 | | 0 (0)| 00:00:01 |
| 6 | NESTED LOOPS | | 1 | 24 | 2 (0)| 00:00:01 |
| 7 | CONNECT BY PUMP | | | | | |
|* 8 | TABLE ACCESS BY INDEX ROWID | EMPLOYEES | 1 | 11 | 1 (0)| 00:00:01 |
|* 9 | INDEX RANGE SCAN | EMP_MANAGER_IX | 6 | | 0 (0)| 00:00:01 |
------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter( EXISTS (SELECT 0 FROM "EMPLOYEES" "B" START WITH "EMPLOYEE_ID"=101 CONNECT BY
"MANAGER_ID"=PRIOR "EMPLOYEE_ID" AND "B"."DEPARTMENT_ID"=:B1))
3 - access("MANAGER_ID"=PRIOR "EMPLOYEE_ID")
filter("B"."DEPARTMENT_ID"=:B1)
5 - access("EMPLOYEE_ID"=101)
8 - filter("B"."DEPARTMENT_ID"=:B1)
9 - access("connect$_by$_pump$_003"."PRIOR employee_id "="MANAGER_ID")
4.如果子查询外面是In就可以展开
SQL> select *
from departments a
where a.department_id in
(SELECT b.department_id
FROM employees b
START WITH employee_id = 101
CONNECT BY PRIOR employee_id = manager_id
)
2 3 4 5 6 7 8 9 ;
6 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 3045523330
---------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 7 | 238 | 6 (17)| 00:00:01 |
| 1 | MERGE JOIN SEMI | | 7 | 238 | 6 (17)| 00:00:01 |
| 2 | TABLE ACCESS BY INDEX ROWID | DEPARTMENTS | 27 | 567 | 2 (0)| 00:00:01 |
| 3 | INDEX FULL SCAN | DEPT_ID_PK | 27 | | 1 (0)| 00:00:01 |
|* 4 | SORT UNIQUE | | 7 | 91 | 4 (25)| 00:00:01 |
| 5 | VIEW | VW_NSO_1 | 7 | 91 | 5 (40)| 00:00:01 |
|* 6 | CONNECT BY WITH FILTERING | | | | | |
| 7 | TABLE ACCESS BY INDEX ROWID | EMPLOYEES | 1 | 11 | 1 (0)| 00:00:01 |
|* 8 | INDEX UNIQUE SCAN | EMP_EMP_ID_PK | 1 | | 0 (0)| 00:00:01 |
| 9 | NESTED LOOPS | | 6 | 144 | 2 (0)| 00:00:01 |
| 10 | CONNECT BY PUMP | | | | | |
| 11 | TABLE ACCESS BY INDEX ROWID| EMPLOYEES | 6 | 66 | 1 (0)| 00:00:01 |
|* 12 | INDEX RANGE SCAN | EMP_MANAGER_IX | 6 | | 0 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("A"."DEPARTMENT_ID"="DEPARTMENT_ID")
filter("A"."DEPARTMENT_ID"="DEPARTMENT_ID")
6 - access("MANAGER_ID"=PRIOR "EMPLOYEE_ID")
8 - access("EMPLOYEE_ID"=101)
12 - access("connect$_by$_pump$_003"."PRIOR employee_id "="MANAGER_ID")