天天看点

测试6——观察Optimizer_index_cost_adj 对执行计划的影响

    在基于cbo的优化器模式下面,oracle会把sql语句的各种执行计划的成本做比较,取其最小的作为其最优执行计划,同时,在决定是用index

scan 还是full table scan 访问一个表的时候,oracle会把index

scan的执行成本转化为fts的成本,然后再根据其成本大小来决定执行计划,这个index

scan 和full table scan 的比值即为 optimizer_index_cost_adj,这个初始化参数代表一个百分比,取值范围在1到10000之间.该参数表示索引扫描和全表扫描成本的比较。缺省值100表示索引扫描成本等价转换与全表扫描成本。

下面的例子具体说明了该参数的不同取值对执行计划的影响(下面的例子不能做为性能调整的根据,只是作为该参数的一个研究型文档,实际在调整该参数的时候,还是参考应用的类型(oltp/olap),及v$system_event 中的db

file sequential read,db file scattered read的具体数值。

建立测试表

SQL> create table t as select * from dba_objects;

SQL> create index t_idx on t(owner);

SQL> SHOW PARAMETER OPTIMIZER_INDEX_COST_ADJ

NAME                                 TYPE        VALUE

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

optimizer_index_cost_adj             integer    100

SQL> SHOW PARAMETER DB_FILE

db_file_multiblock_read_count       integer     128

SQL> set autotrace traceonly explain;

SQL> select * from t where owner='HR';

Execution Plan

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

Plan hash value: 1579008347

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

| Id  | Operation   | Name  | Rows  | Bytes | Cost (%CPU)| Time    |

|   0 | SELECT STATEMENT   | 

 |  2500 |505K|92

  (0)| 00:00:02 |

|   1 |  TABLE ACCESS BY INDEX ROWID| T     |  2500 |505K|92

|*  2 |   INDEX RANGE SCAN   | T_INX |  2500 | 

 | 8   (0)| 00:00:01 |

Predicate Information (identified by operation id):

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

   2 - access("OWNER"='HR')

Note

-----

   - dynamic sampling used for this statement (level=2)

专门走一次全表扫描,看下cost是多少:

SQL>   select /*+ FULL(T) */ * FROM T WHERE owner='HR';

SQL>   select /*+ FULL(T) */ * FROM T WHERE owner='HR';

Plan hash value: 1601196873

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

| Id  | Operation | Name | Rows  | Bytes | Cost (%CPU)| Time|

|   0 | SELECT STATEMENT  ||  2500 |   505K|  1591 

(1)| 00:00:20 |

|*  1 |  TABLE ACCESS FULL| T|  2500 |   505K|  1591   (1)| 00:00:20 |

   1 - filter("OWNER"='HR')

默认的optimizer_index_cost_adj

=100,全表扫描的成本是1591,索引范围扫描的成本92,此时索引扫描的成本要比全表扫描的成本低,调整optimizer_index_cost_adj 参数,调整的基点: 全表扫描成本/索引扫描成本

SQL> SET AUTOTRACE OFF;

SQL> SELECT 1591/92*100 FROM DUAL;

1591/92*100

-----------

 1729.34783

接下来,是重点,我们取一个比这个基数略大的数值:1731

SQL> ALTER SESSION SET OPTIMIZER_INDEX_COST_ADJ=1731;

Session altered.

SQL>

SHOW PARAMETER OPTIMIZER_INDEX_COST_ADJ

NAME     TYPE

VALUE

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

optimizer_index_cost_adj     integer1731

set autotrace traceonly explain;

| Id  | Operation  | Name | Rows  | Bytes | Cost (%CPU)| Time|

|   0 | SELECT STATEMENT  | |  2500 |   505K|  1591   (1)| 00:00:20 |

|*  1 |  TABLE ACCESS FULL| T |  2500 |   505K|  1591   (1)| 00:00:20 |

可以看到,此时奇怪的事情发生了,这个查询居然是走的全表扫描,而不是索引,这个参数到底是如何决定的呢?

原来: 在比较的时候,Oracle会把索引扫描的成本转换为全表扫描的成本,和全表扫描的COST进行比较.这个转换需要一个转换因子.就是optimizer_index_cost_adj:

optimizer_index_cost_adj * (Index Scan Cost) = 等价的 Full Scan Cost(比如刚才1731*92=159252 > 1591*100,所以选择了全表扫描,因为这个参数的权重让oracle决定走全表扫描的cost更低)

这个 等价的 Full Scan Cost 就是来和全表扫描成本进行比较的.

而这个转换因子的临界值实际上就是Full Scan Cost 和 Index Scan Cost的比值.

即:

optimizer_index_cost_adj = Full Scan Cost / Index

Scan Cost(刚才1591/92 *100 =1731)

然后,我们把这个因子降低一点,看看是不是就会走索引呢?继续实验:

ALTER SESSION SET OPTIMIZER_INDEX_COST_ADJ=1725;

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

| Id  | Operation    | Name  | Rows  | Bytes | Cost (%CPU)| Time|

|   0 | SELECT STATEMENT    |   |  2500 |

505K|  1589   (1)| 00:00:20 |

|   1 |  TABLE ACCESS BY INDEX ROWID| T     |  2500 |505K|  1589   (1)| 00:00:20 |

|*  2 |   INDEX RANGE SCAN    | T_INX |  2500 |   |

138   (0)| 00:00:02 |

果然,此时又走的索引,但是cost变成了1589(我们知道full table scan的成本是1591),所以选择了成本较少的,那么这个值是怎么来的呢?

是实际的cost*optimizer_index_cost_adj 得到的(1589/1725=0.9211=92/100)

综上,我们明白了这个参数可以理解为一个权重的值,这个值越高,index scan的权重越小,越倾向于使用full table scan。一般OLTP系统里,建议设置较小的值10-50,这样就会有更多的查询走索引扫描,参考http://www.dba-oracle.com/oracle_tips_cost_adj.htm

For some OLTP systems, re-setting this parameter to a smaller value (between 10- to 30) may result in huge performance gains