分享
 
 
 

Oracle 10g(10.1.0.2)中的OPTIMIZER_INDEX_COST_ADJ

王朝oracle·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

Oracle 10g(10.1.0.2)中的OPTIMIZER_INDEX_COST_ADJ

Tom Kyte的新书Effective Oracle by Design的第6章 Getting the Most Out of the Cost-Based Optimizer中介绍了参数OPTIMIZER_INDEX_COST_ADJ,并认为可以理解为Oracle执行多块(MultiBlock)I/O(比如全表扫描)的代价与执行单块(Single-block)I/O代价的相对比例。Tom指出,9i下该参数缺省值为100,意即二者拥有相同的代价,若减小,则CBO倾向于使用索引(即单块I/O),反之则倾向于全表扫描(多块I/O)。Tom同样给出了一个不错的例子。

在自己的手提上试验了一下,硬盘大小原因,只装了一个Oracle 10g(10.1.0.2),谁知就发现该参数在10g下取值发生了改变。我们先来看一下参照Tom的实验:

A. 创建数据表。

SQL> drop table t1;

表已删除。

SQL> drop table t2;

表已删除。

SQL> create table t1

2 as

3 select mod(rownum,1000) id,rpad('x',300,'x') data

4 from all_objects

5 where rownum<=5000;

表已创建。

SQL> ed

已写入 file afiedt.buf

1 create table t2

2 as

3 select rownum id,rpad('x',300,'x') data

4 from all_objects

5* where rownum<=1000

SQL> /

表已创建。

B.创建索引并分析。

SQL> create index idx_t1 on t1(id);

索引已创建。

SQL> create index idx_t2 on t2(id);

索引已创建。

SQL> ed

已写入 file afiedt.buf

1 begin

2 dbms_stats.gather_table_stats

3 (user,'T1',method_opt=>'for all indexed columns',cascade=>true);

4 dbms_stats.gather_table_stats

5 (user,'T2',method_opt=>'for all indexed columns',cascade=>true);

6* end;

SQL> /

PL/SQL 过程已成功完成。

C.查询缺省值,并设置好环境。

SQL> set autot off

SQL> show parameters optimizer_index_cost_adj;

NAME TYPE VALUE

------------------------------------ ----------- ------------------------------

optimizer_index_cost_adj integer 100

SQL> set autot traceonly exp stat;

D.在缺省值下查询的结果。

SQL> ed

已写入 file afiedt.buf

1 select * from t1,t2

2 where t1.id=t2.id

3* and t2.id between 50 and 55

SQL> /

已选择30行。

执行计划

----------------------------------------------------------

0 SELECT STATEMENT Optimizer=CHOOSE (Cost=13 Card=5 Bytes=1000

)

1 0 TABLE ACCESS (BY INDEX ROWID) OF 'T1' (TABLE) (Cost=2 Card

=1 Bytes=100)

2 1 NESTED LOOPS (Cost=13 Card=5 Bytes=1000)

3 2 TABLE ACCESS (BY INDEX ROWID) OF 'T2' (TABLE) (Cost=3

Card=5 Bytes=500)

4 3 INDEX (RANGE SCAN) OF 'IDX_T2' (INDEX) (Cost=2 Card=

5)

5 2 INDEX (RANGE SCAN) OF 'IDX_T1' (INDEX) (Cost=1 Card=1)

统计信息

----------------------------------------------------------

367 recursive calls

0 db block gets

101 consistent gets

0 physical reads

0 redo size

1507 bytes sent via SQL*Net to client

523 bytes received via SQL*Net from client

3 SQL*Net roundtrips to/from client

12 sorts (memory)

0 sorts (disk)

30 rows processed

E.修改参数值,注意,引用Tom的结论,9i中这个值在0-100之间,而10g呢?

SQL> alter session set optimizer_index_cost_adj=0;

ERROR:

ORA-00068: 值 0 对参数 optimizer_index_cost_adj 无效, 必须在 1 和 10000 之间

SQL> alter session set optimizer_index_cost_adj=1;

会话已更改。

SQL> ed

已写入 file afiedt.buf

1 select * from t1,t2

2 where t1.id=t2.id

3* and t2.id between 50 and 55

SQL> /

已选择30行。

执行计划

----------------------------------------------------------

0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=5 Bytes=1000)

1 0 TABLE ACCESS (BY INDEX ROWID) OF 'T1' (TABLE) (Cost=1 Card

=1 Bytes=100)

2 1 NESTED LOOPS (Cost=2 Card=5 Bytes=1000)

3 2 TABLE ACCESS (BY INDEX ROWID) OF 'T2' (TABLE) (Cost=1

Card=5 Bytes=500)

4 3 INDEX (RANGE SCAN) OF 'IDX_T2' (INDEX) (Cost=2 Card=

5)

5 2 INDEX (RANGE SCAN) OF 'IDX_T1' (INDEX) (Cost=1 Card=1)

统计信息

----------------------------------------------------------

1 recursive calls

0 db block gets

48 consistent gets

0 physical reads

0 redo size

1507 bytes sent via SQL*Net to client

523 bytes received via SQL*Net from client

3 SQL*Net roundtrips to/from client

0 sorts (memory)

0 sorts (disk)

30 rows processed

SQL> alter session set optimizer_index_cost_adj=50;

会话已更改。

SQL> ed

已写入 file afiedt.buf

1 select * from t1,t2

2 where t1.id=t2.id

3* and t2.id between 50 and 55

SQL> /

已选择30行。

执行计划

----------------------------------------------------------

0 SELECT STATEMENT Optimizer=CHOOSE (Cost=7 Card=5 Bytes=1000)

1 0 TABLE ACCESS (BY INDEX ROWID) OF 'T1' (TABLE) (Cost=1 Card

=1 Bytes=100)

2 1 NESTED LOOPS (Cost=7 Card=5 Bytes=1000)

3 2 TABLE ACCESS (BY INDEX ROWID) OF 'T2' (TABLE) (Cost=2

Card=5 Bytes=500)

4 3 INDEX (RANGE SCAN) OF 'IDX_T2' (INDEX) (Cost=2 Card=

5)

5 2 INDEX (RANGE SCAN) OF 'IDX_T1' (INDEX) (Cost=1 Card=1)

统计信息

----------------------------------------------------------

1 recursive calls

0 db block gets

48 consistent gets

0 physical reads

0 redo size

1507 bytes sent via SQL*Net to client

523 bytes received via SQL*Net from client

3 SQL*Net roundtrips to/from client

0 sorts (memory)

0 sorts (disk)

30 rows processed

F.继续修改参数值,改大。

SQL> alter session set optimizer_index_cost_adj=200;

会话已更改。

SQL> ed

已写入 file afiedt.buf

1 select * from t1,t2

2 where t1.id=t2.id

3* and t2.id between 50 and 55

SQL> /

已选择30行。

执行计划

----------------------------------------------------------

0 SELECT STATEMENT Optimizer=CHOOSE (Cost=26 Card=5 Bytes=1000

)

1 0 TABLE ACCESS (BY INDEX ROWID) OF 'T1' (TABLE) (Cost=4 Card

=1 Bytes=100)

2 1 NESTED LOOPS (Cost=26 Card=5 Bytes=1000)

3 2 TABLE ACCESS (BY INDEX ROWID) OF 'T2' (TABLE) (Cost=6

Card=5 Bytes=500)

4 3 INDEX (RANGE SCAN) OF 'IDX_T2' (INDEX) (Cost=2 Card=

5)

5 2 INDEX (RANGE SCAN) OF 'IDX_T1' (INDEX) (Cost=1 Card=1)

统计信息

----------------------------------------------------------

1 recursive calls

0 db block gets

48 consistent gets

0 physical reads

0 redo size

1507 bytes sent via SQL*Net to client

523 bytes received via SQL*Net from client

3 SQL*Net roundtrips to/from client

0 sorts (memory)

0 sorts (disk)

30 rows processed

SQL> alter session set optimizer_index_cost_adj=500;

会话已更改。

SQL> ed

已写入 file afiedt.buf

1 select * from t1,t2

2 where t1.id=t2.id

3* and t2.id between 50 and 55

SQL> /

已选择30行。

执行计划

----------------------------------------------------------

0 SELECT STATEMENT Optimizer=CHOOSE (Cost=63 Card=5 Bytes=1000

)

1 0 TABLE ACCESS (BY INDEX ROWID) OF 'T1' (TABLE) (Cost=10 Car

d=1 Bytes=100)

2 1 NESTED LOOPS (Cost=63 Card=5 Bytes=1000)

3 2 TABLE ACCESS (FULL) OF 'T2' (TABLE) (Cost=13 Card=5 By

tes=500)

4 2 INDEX (RANGE SCAN) OF 'IDX_T1' (INDEX) (Cost=1 Card=1)

统计信息

----------------------------------------------------------

1 recursive calls

0 db block gets

90 consistent gets

0 physical reads

0 redo size

1507 bytes sent via SQL*Net to client

523 bytes received via SQL*Net from client

3 SQL*Net roundtrips to/from client

0 sorts (memory)

0 sorts (disk)

30 rows processed

SQL> alter session set optimizer_index_cost_adj=1000;

会话已更改。

SQL> ed

已写入 file afiedt.buf

1 select * from t1,t2

2 where t1.id=t2.id

3* and t2.id between 50 and 55

SQL> /

已选择30行。

执行计划

----------------------------------------------------------

0 SELECT STATEMENT Optimizer=CHOOSE (Cost=66 Card=5 Bytes=1000

)

1 0 HASH JOIN (Cost=66 Card=5 Bytes=1000)

2 1 TABLE ACCESS (FULL) OF 'T2' (TABLE) (Cost=13 Card=5 Byte

s=500)

3 1 TABLE ACCESS (FULL) OF 'T1' (TABLE) (Cost=52 Card=26 Byt

es=2600)

统计信息

----------------------------------------------------------

1 recursive calls

0 db block gets

271 consistent gets

213 physical reads

0 redo size

1651 bytes sent via SQL*Net to client

523 bytes received via SQL*Net from client

3 SQL*Net roundtrips to/from client

0 sorts (memory)

0 sorts (disk)

30 rows processed

SQL> alter session set optimizer_index_cost_adj=10000;

会话已更改。

SQL> ed

已写入 file afiedt.buf

1 select * from t1,t2

2 where t1.id=t2.id

3* and t2.id between 50 and 55

SQL> /

已选择30行。

执行计划

----------------------------------------------------------

0 SELECT STATEMENT Optimizer=CHOOSE (Cost=66 Card=5 Bytes=1000

)

1 0 HASH JOIN (Cost=66 Card=5 Bytes=1000)

2 1 TABLE ACCESS (FULL) OF 'T2' (TABLE) (Cost=13 Card=5 Byte

s=500)

3 1 TABLE ACCESS (FULL) OF 'T1' (TABLE) (Cost=52 Card=26 Byt

es=2600)

统计信息

----------------------------------------------------------

1 recursive calls

0 db block gets

271 consistent gets

0 physical reads

0 redo size

1651 bytes sent via SQL*Net to client

523 bytes received via SQL*Net from client

3 SQL*Net roundtrips to/from client

0 sorts (memory)

0 sorts (disk)

30 rows processed

G.现在看看对性能的影响。

SQL> set timing on

SQL> alter session set optimizer_index_cost_adj=100;

会话已更改。

已用时间: 00: 00: 00.00

SQL> ed

已写入 file afiedt.buf

1 select * from t1,t2

2 where t1.id=t2.id

3* and t2.id between 50 and 55

SQL> /

已选择30行。

已用时间: 00: 00: 00.02

执行计划

----------------------------------------------------------

0 SELECT STATEMENT Optimizer=CHOOSE (Cost=13 Card=5 Bytes=1000

)

1 0 TABLE ACCESS (BY INDEX ROWID) OF 'T1' (TABLE) (Cost=2 Card

=1 Bytes=100)

2 1 NESTED LOOPS (Cost=13 Card=5 Bytes=1000)

3 2 TABLE ACCESS (BY INDEX ROWID) OF 'T2' (TABLE) (Cost=3

Card=5 Bytes=500)

4 3 INDEX (RANGE SCAN) OF 'IDX_T2' (INDEX) (Cost=2 Card=

5)

5 2 INDEX (RANGE SCAN) OF 'IDX_T1' (INDEX) (Cost=1 Card=1)

统计信息

----------------------------------------------------------

0 recursive calls

0 db block gets

48 consistent gets

0 physical reads

0 redo size

1507 bytes sent via SQL*Net to client

523 bytes received via SQL*Net from client

3 SQL*Net roundtrips to/from client

0 sorts (memory)

0 sorts (disk)

30 rows processed

SQL> alter session set optimizer_index_cost_adj=1;

会话已更改。

已用时间: 00: 00: 00.00

SQL> ed

已写入 file afiedt.buf

1 select * from t1,t2

2 where t1.id=t2.id

3* and t2.id between 50 and 55

SQL> /

已选择30行。

已用时间: 00: 00: 00.02

执行计划

----------------------------------------------------------

0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=5 Bytes=1000)

1 0 TABLE ACCESS (BY INDEX ROWID) OF 'T1' (TABLE) (Cost=1 Card

=1 Bytes=100)

2 1 NESTED LOOPS (Cost=2 Card=5 Bytes=1000)

3 2 TABLE ACCESS (BY INDEX ROWID) OF 'T2' (TABLE) (Cost=1

Card=5 Bytes=500)

4 3 INDEX (RANGE SCAN) OF 'IDX_T2' (INDEX) (Cost=2 Card=

5)

5 2 INDEX (RANGE SCAN) OF 'IDX_T1' (INDEX) (Cost=1 Card=1)

统计信息

----------------------------------------------------------

0 recursive calls

0 db block gets

48 consistent gets

0 physical reads

0 redo size

1507 bytes sent via SQL*Net to client

523 bytes received via SQL*Net from client

3 SQL*Net roundtrips to/from client

0 sorts (memory)

0 sorts (disk)

30 rows processed

SQL> alter session set optimizer_index_cost_adj=10000;

会话已更改。

已用时间: 00: 00: 00.00

SQL> ed

已写入 file afiedt.buf

1 select * from t1,t2

2 where t1.id=t2.id

3* and t2.id between 50 and 55

SQL> /

已选择30行。

已用时间: 00: 00: 00.03

执行计划

----------------------------------------------------------

0 SELECT STATEMENT Optimizer=CHOOSE (Cost=66 Card=5 Bytes=1000

)

1 0 HASH JOIN (Cost=66 Card=5 Bytes=1000)

2 1 TABLE ACCESS (FULL) OF 'T2' (TABLE) (Cost=13 Card=5 Byte

s=500)

3 1 TABLE ACCESS (FULL) OF 'T1' (TABLE) (Cost=52 Card=26 Byt

es=2600)

统计信息

----------------------------------------------------------

0 recursive calls

0 db block gets

271 consistent gets

0 physical reads

0 redo size

1651 bytes sent via SQL*Net to client

523 bytes received via SQL*Net from client

3 SQL*Net roundtrips to/from client

0 sorts (memory)

0 sorts (disk)

30 rows processed

来详细分析一下。

首先,10g中OPTIMIZER_INDEX_COST_ADJ的取值范围发生了改变。9i中为0-100,而10g中为1-10000。

其次,由于测试环境的不同,Tom的测试结果是在缺省值(100)的环境下,就已经和上面取值500时一样了,即对T2全表扫描而T1使用索引。Tom试验中,减小取值直至0,访问路径就变成使用两个索引,而并不会出现均不使用索引的情况。除去系统的不同(可能导致取缺省值时访问路径是否一致),只看变化趋势,显然10g中灵活性更高,1-10000的取值使得CBO可以覆盖所有的访问路径。另一方面,正如Tom的结论所说,OPTIMIZER_INDEX_COST_ADJ的取值越大,优化器越倾向于使用全表扫描,取值越小,优化器越倾向于使用索引。

再次,我们对比相同访问路径下的不同点。在取值从1变化到200(1-50-100-200)的过程中,优化器计算出的代价是持续增长的,而从1000到10000则是不变的。这说明这个参数与索引I/O的代价有关,而和全表扫描并无关系,这与Tom所说的并不矛盾,不过显然更精确一点。

最后我们其实应该看到,虽然有如上所说的代价变化问题,同一访问路径下实际的运行性能并无区别,由于数据量比较小,上面的例子也许不能很好的说明这一点,不过想想Oracle用相同的路径去执行,也没有理由不同性能吧。

好,来看看官方文档吧。10G的官方文档(Reference)中对这个参数描述如下:

OPTIMIZER_INDEX_COST_ADJ

Parameter type Integer 参数类型为整数

Default value 100 缺省值为100

Modifiable ALTER SESSION, ALTER SYSTEM 可通过ALTER SESSION, ALTER SYSTEM来修改

Range of values 1 to 10000 取值范围是1-10000

OPTIMIZER_INDEX_COST_ADJ lets you tune optimizer behavior for access path selection to be more or less index friendly—that is, TO MAKE THE OPTIMIZER MORE OR LESS PRONE TO SELECTING AN INDEX ACCESS PATH OVER A FULL TABLE SCAN.

The default for this parameter is 100 percent, at which the optimizer evaluates index access paths at the regular cost. Any other value makes the optimizer evaluate the access path at that percentage of the regular cost. For example, a setting of 50 makes the index access path look half as expensive as normal.

Note:

The adjustment does not apply to user-defined cost functions for domain indexes.

注意:调整对用户为域索引自定义的代价函数无效。

描述的第一段正证实了参数的作用。第二段值得注意,正如Tom所说(我觉得如果他把原文versus前后颠倒一下会更好,即单块I/O代价比之多块I/O),参数表达了索引访问代价对比

普通(表扫描)代价的比值。不过还有一个疑问我暂时还没办法想通,什么条件下索引I/O居然比扫描慢100倍(取值10000)?

结论:

OPTIMIZER_INDEX_COST_ADJ通过指明索引I/O代价与扫描全表I/O代价的相对比值来影响CBO的行为,取值越小,CBO越倾向于使用索引,取值越大,越倾向于全表扫描。而缺省值100,指明缺省下,二者的代价是相等。与9i不同的是,10g中OPTIMIZER_INDEX_COST_ADJ的取值范围从0-100改为1-10000,相信是更合理的取值(至少按照文档的说明,作为代价的比值,取0是不合适的,除非说索引I/O的代价相对于全表扫描I/O代价是无穷小的)。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有