|
10g下做测试
SAMPLE
表t记录50207条,
distinct owner 24
[email=T@ORA]T@ORA>DESC[/email] T
Name Null? Type
---------------------------------------------------------------------- -------- -----------------------------------------------
OWNER VARCHAR2(30)
OBJECT_NAME NOT NULL VARCHAR2(30)
SUBOBJECT_NAME VARCHAR2(30)
OBJECT_ID NOT NULL NUMBER
DATA_OBJECT_ID NUMBER
OBJECT_TYPE VARCHAR2(19)
CREATED NOT NULL DATE
LAST_DDL_TIME NOT NULL DATE
TIMESTAMP VARCHAR2(19)
STATUS VARCHAR2(7)
TEMPORARY VARCHAR2(1)
GENERATED VARCHAR2(1)
SECONDARY VARCHAR2(1)
[email=T@ORA]T@ORA>SELECT[/email] COUNT(*) FROM T;
COUNT(*)
----------
50207
Elapsed: 00:00:00.01
[email=T@ORA]T@ORA>select/*+gather_plan_statistics*/[/email] count(OWNER) from t WHERE OWNER NOT IN (SELECT/*+NO_UNNEST*/ OWNER FROM T);
COUNT(OWNER)
------------
0
Elapsed: 00:00:00.57
[email=T@ORA]T@ORA>SELECT[/email] * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL,NULL,'ALLSTATS LAST'));
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------
SQL_ID 1xj0j83009vdz, child number 0
-------------------------------------
select/*+gather_plan_statistics*/ count(OWNER) from t WHERE OWNER NOT IN
(SELECT/*+NO_UNNEST*/ OWNER FROM T)
Plan hash value: 2615818063
--------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
--------------------------------------------------------------------------------------
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.58 | 32895 |
|* 2 | FILTER | | 1 | | 0 |00:00:00.58 | 32895 |
| 3 | TABLE ACCESS FULL| T | 1 | 50207 | 50207 |00:00:00.15 | 694 |
|* 4 | TABLE ACCESS FULL| T | 59 | 2510 | 59 |00:00:00.53 | 32201 |
--------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter( IS NULL)
4 - filter(LNNVL("OWNER"<>:B1))
22 rows selected.
Elapsed: 00:00:00.31
按照正常的filter的操作,对计划行3中 返回的的每一行,都需要执行一次计划行4
而实际上上面的计划行4 |* 4 | TABLE ACCESS FULL| T | 59 |
starts = 59,而不是 50207次(t中总记录数),最佳执行计划这里应该只执行24次(就是disinct owner的数),这个可以从执行计划的cost中可以可能出来,
oracle优化器在计算代价的时候就考虑了这个问题
----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 6 | 7602 (2)| 00:00:39 |
| 1 | SORT AGGREGATE | | 1 | 6 | | |
|* 2 | FILTER | | | | | |
| 3 | TABLE ACCESS FULL| T | 50207 | 294K| 361 (2)| 00:00:02 |
|* 4 | TABLE ACCESS FULL| T | 2510 | 15060 | 362 (2)| 00:00:02 |
----------------------------------------------------------------------------
看cost列,行3 cost = 361 行4 cost = 362
361+362*20 = 7602
因为这里oracle认为distnct owner 数为20(这个是统计信息问题),所以filter里面的 table access full只需要执行20次,而不是50207次,代价计算也反映出这个优化,
实际执行的时候因为数据关系不是执行了20次,而是59次,但是比起50207次性能提高还是特别明显的
再看一个更明显的例子
CREATE TABLE EMP AS SELECT ROWNUM EMPNO,ROWNUM SAL,MOD(ROWNUM,6) DEPTNO FROM ALL_OBJECTS NOLOGGING;
distinct deptno 6
[email=T@ORA]T@ORA>select/*+gather_plan_statistics*/[/email] count(*) from emp o WHERE sal > (SELECT/*+NO_UNNEST*/ avg(sal) FROM emp where emp.deptno = o.deptno);
COUNT(*)
----------
25104
Elapsed: 00:00:00.20
[email=T@ORA]T@ORA>SELECT[/email] * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL,NULL,'ALLSTATS'));
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------
SQL_ID d9r5a705ff1zk, child number 0
-------------------------------------
select/*+gather_plan_statistics*/ count(*) from emp o WHERE sal >
(SELECT/*+NO_UNNEST*/ avg(sal) FROM emp where emp.deptno = o.deptno)
Plan hash value: 1040767149
---------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
---------------------------------------------------------------------------------------
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.13 | 875 |
|* 2 | FILTER | | 1 | | 25104 |00:00:00.19 | 875 |
| 3 | TABLE ACCESS FULL | EMP | 1 | 50208 | 50208 |00:00:00.15 | 125 |
| 4 | SORT AGGREGATE | | 6 | 1 | 6 |00:00:00.06 | 750 |
|* 5 | TABLE ACCESS FULL| EMP | 6 | 8368 | 50208 |00:00:00.15 | 750 |
---------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("SAL">)
5 - filter("EMP"."DEPTNO"=:B1)
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 8 | 512 (8)| 00:00:03 |
| 1 | SORT AGGREGATE | | 1 | 8 | | |
|* 2 | FILTER | | | | | |
| 3 | TABLE ACCESS FULL | EMP | 50208 | 392K| 73 (7)| 00:00:01 |
| 4 | SORT AGGREGATE | | 1 | 8 | | |
|* 5 | TABLE ACCESS FULL| EMP | 8368 | 66944 | 73 (7)| 00:00:01 |
-----------------------------------------------------------------------------
cost 512 接近于 73 + 73*6 |
|