欢迎投稿

今日深度:

CBO学习之一What do you mean by Cost

CBO学习之一What do you mean by Cost


CBO学习之一What do you mean by Cost
 
Mr. Lewis代码如下,注释部分略作改动:
 
[sql] 
/*  
Script:     first_rows.sql  
Author:     Jonathan Lewis  
Dated:      June 2002  
Purpose:    Problems with FIRST_ROWS optimisation  
  
Last tested   
    10.1.0.4  
     9.2.0.6  
     8.1.7.4  
  
The FIRST_ROWS optimizer does not have a sensible strategy  
for dealing with optimisation of an ORDER BY (and possibly  
other variants such as GROUP BY) when it finds it can use  
an index to do the ORDER BY "free of charge".  
  
This example demonstrates the point. Without the in-line  
view, Oracle does a full scan on the primary key index to  
return the 100 required rows in order, at a total cost  
and total execution time that is much higher than that of  
using the required index.  
  
Of course, it is arguably the case that this is correct  
behaviour if we assume that the time to the first row is  
important, and therefore we avoid collecting a large number  
of rows and sorting them.  In practice, this is perhaps not  
really likely to be the case.  
  
Bug number 670328 applies  
  
Parameter _sort_elimination_cost_ratio affects the break  
point between optimising for the WHERE clause and optimising  
for the ORDER BY clause.  
  
If the parameter is zero, the ORDER BY clause takes precedence  
If the parameter is non-zero, then the index is used if the cost   
of using it is less than the cost of doing the sort multiplied   
by the value of the parameter.  
  
Special note for 10g:  
The parameter still has the same effect in general, but zero  
now means zero, not (effectively) infinity.  The default of  
zero will now effectively ignore the index option unless it  
is actually cheaper than the non-index option. A non-zero  
value will behave as it always used to  
*/  
  
--start setenv  
  
drop table t1;  
  
begin  
    begin       execute immediate 'purge recyclebin';  
    exception   when others then null;  
    end;  
  
    begin       execute immediate 'begin dbms_stats.delete_system_stats; end;';  
    exception   when others then null;  
    end;  
  
    begin       execute immediate 'alter session set "_optimizer_cost_model"=io';  
    exception   when others then null;  
    end;  
  
end;  
/  
  
create table t1 as  
select  
    rownum          id,  
--  mod(rownum,100)     modded,  
    mod(rownum,300)     modded,  
    lpad(rownum,1000)   padding  
from  
    all_objects  
where  
    rownum <= 10000  
;  
  
alter table t1 add constraint t1_pk primary key(id);  
create index t1_mod on t1(modded);  
  
begin  
    dbms_stats.gather_table_stats(  
        user,  
        't1',  
        cascade => true,  
        estimate_percent => null,  
        method_opt => 'for all columns size 1'  
    );  
end;  
/  
  
alter session set optimizer_mode=first_rows;  
  
set autotrace traceonly explain  
  
spool first_rows  
  
/*  
Get a base-line cost and plan for acquiring the rows  
*/  
  
select  *  
from    t1  
where   modded = 0  
;  
  
/*  
See what happens if we add an 'order by primary key'.  
*/  
  
select  *  
from    t1  
where   modded = 0  
order by   
    id  
;  
  
/*  
Block the PK index from being used for ordering, and see  
that Oracle could notionally get a better path. Strangely  
the cost varies depending on the strategy used for blocking  
the index. On my 9.2.0.6 test, the no_merge hint managed to  
reduce the lengths of the rows to be sorted, and therefore  
calculated a smaller cost.  
*/  
  
/*  
Block the index with a no_merge hint  
*/  
  
select * from (  
select  /*+ no_merge */   
    *  
from    t1  
where   modded = 0  
)  
order by   
    id  
;  
  
  
/*  
Block the index with a no_index hint  
*/  
  
select  /*+ no_index(t1,t1_pk) */  
    *  
from    t1  
where   modded = 0  
order by   
    id  
;  
  
set autotrace off  
  
/*  
The costs under 8i are:  
    Using the PK index to avoid the sort:       1,450  
    Block the PK index (no_index) and sorting:  43  
  
Cost ratio: 1450/43 = 33.729, so we test   
    _sort_elimination_cost_ratio at 33 and 34  
  
At 33:  43 * 33 = 1,419:  so the PK nosort should be ignored  
At 34:  43 * 34 = 1,462:  so the PK nosort falls inside the limit.  
  
(Because of a change in the cost in 10g, the break point  
for the parameter was 32/33 on my 10g system)  
*/  
  
set autotrace traceonly explain   
  
alter session set "_sort_elimination_cost_ratio" = 34;  
  
/*  
Cost ratio set to 34 - PK path should be accepted  
*/  
  
select  
    *  
from    t1  
where   modded = 0  
order by   
    id  
;  
  
alter session set "_sort_elimination_cost_ratio" = 33;  
  
/*  
Cost ratio set to 33 - PK NOSORT should be too expensive  
*/  
  
select  
    *  
from    t1  
where   modded = 0  
order by   
    id  
;  
  
set autotrace off  
  
spool off  
 
 
参数“_sort_elimination_cost_ratio”含义如下(转自http://space.itpub.net/22034023/viewspace-716217):
 
create table t1 as select * from dba_objects where object_id is not null;
alter table t1 add constraint t1_pk primary key(object_id);
create index t1_ind on t1(object_type);
alter session set optimizer_mode=first_rows;
alter session set "_sort_elimination_cost_ratio" = 0;
 
以上脚本创建了一张表,表的主键是object_id,表上有一个普通索引object_type.
 
set autotrace traceonly
select        *
  2  from       t1
  3  where      object_type = 'TABLE'
  4  order by
  5     object_id
  6  ;
 
2060 rows selected.
 
 
Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT ptimizer=FIRST_ROWS (Cost=276 Card=423 Bytes=36378)
   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'T1' (Cost=276 Card=423 Bytes=36378)
   2    1     INDEX (FULL SCAN) OF 'T1_PK' (UNIQUE) (Cost=23 Card=10986)
 
我们看到默认的执行计划走了主键索引的index full scan.算出来的cost是276.
 
select        /*+ no_index(t1,t1_pk) */
  2  *
  3  from       t1
  4  where      object_type = 'TABLE'
  5  order by
  6     object_id
  7  ;
 
2060 rows selected.
 
 
Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT ptimizer=FIRST_ROWS (Cost=46 Card=423 Bytes=36378)
   1    0   SORT (ORDER BY) (Cost=46 Card=423 Bytes=36378)
   2    1     TABLE ACCESS (BY INDEX ROWID) OF 'T1' (Cost=32 Card=423Bytes=36378)
   3    2       INDEX (RANGE SCAN) OF 'T1_IND' (NON-UNIQUE) (Cost=1 Card=423)
 
通过为语句增加hint的方式,查询计划走了index RANGE scan.这个时候的cost是46.
 
select 276/46 from dual;
 
    276/46
----------
         6
默认的查询计划(INDEX pk full scan)的cost是走object_type索引查询计划的6倍。
我们通过设置_sort_elimination_cost_ratio的值小于6,准确点说,小于6大于0的整数都可以。
 
alter session set "_sort_elimination_cost_ratio" =5;
 
Session altered.
 
select
  2  *
  3  from       t1
  4  where      object_type = 'TABLE'
  5  order by
  6     object_id
  7  ;
 
2060 rows selected.
 
 
Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT ptimizer=FIRST_ROWS (Cost=46 Card=423 Bytes=36378)
   1    0   SORT (ORDER BY) (Cost=46 Card=423 Bytes=36378)
   2    1     TABLE ACCESS (BY INDEX ROWID) OF 'T1' (Cost=32 Card=423Bytes=36378)
   3    2       INDEX (RANGE SCAN) OF 'T1_IND' (NON-UNIQUE) (Cost=1 Card=423)
 
可以看到默认的执行计划已经走到了object_type索引的range scan.
 
如果设置参数_sort_elimination_cost_ratio的值大于6,那么查询计划依然会走主键列的index full scan.
 
alter session set "_sort_elimination_cost_ratio" =6/7(只要大等于6);
 
Session altered.
 
select
*
 from  t1
where   object_type = 'TABLE'
order by
        object_id
;
 
2060 rows selected.
 
 
Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT ptimizer=FIRST_ROWS (Cost=276 Card=423 Bytes=36378)
   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'T1' (Cost=276 Card=423 Bytes=36378)
   2    1     INDEX (FULL SCAN) OF 'T1_PK' (UNIQUE) (Cost=23 Card=10986)
 
可以看到 _sort_elimination_cost_ratio 的含义。
如果不走排序的成本/走排序的成本 >  _sort_elimination_cost_ratio.那么执行计划会走排序。
如果不走排序的成本/走排序的成本 <  _sort_elimination_cost_ratio.那么执行计划不会走排序。
_sort_elimination_cost_ratio=0是一个比较特殊的值,代表任何时候都要消减排序,即使排序的成本的是无穷大。
如果想取消这个特性,那么就把这个参数值设置成1。
有一点没想明白,这个参数值9I就有的。这个特性导致的问题是,走了耗费时间更长的index full scan.
如果这个特性存在问题,那么9I就应该存在问题,可是网上大多数网友遇到的问题是,升级到10G以后出现了这个问题。
 

www.htsjk.Com true http://www.htsjk.com/oracle/21548.html NewsArticle CBO学习之一What do you mean by Cost CBO学习之一What do you mean by Cost Mr. Lewis代码如下,注释部分略作改动: [sql] /* Script: first_rows.sql Author: Jonathan Lewis Dated: June 2002 Purpose: Problems with FIRST_ROWS op...
相关文章
    暂无相关文章
评论暂时关闭