关于如何参数OPTIMIZER_INDEX_COST_ADJ和参数OPTIMIZER_INDEX_CACHING

关于oracle优化器的环境设置,有很多参数都会影响优化器的工作方式,具体的参数可见http://docs.oracle.com/cd/B28359_01/server.111/b28274/optimops.htm#BABDECGJ,共有CURSOR_SHARING,DB_FILE_MULTIBLOCK_READ_COUNT,OPTIMIZER_INDEX_CACHING,OPTIMIZER_INDEX_COST_ADJ,OPTIMIZER_MODE,PGA_AGGREGATE_TARGET,STAR_TRANSFORMATION_ENABLED,这么几个参数,其中OPTIMIZER_INDEX_CACHING,OPTIMIZER_INDEX_COST_ADJ 是比较难以理解的。本文就自己的学习经验与大家共享。

               

1.      老外的理解

此参数2与优化器中的cost理解息息相关,故首先我们来看看老外对CBO优化器的理解,详见http://www.docin.com/p-360645801.html,或者 http://blog.itpub.net/7185924/viewspace-837454/

文章不在赘述,总结了几点

1.oracle的cost=IO + CPU/1000 + NetIO*1.5。这里的IO代表物理IO,CPU代表逻辑IO,NetIO表示从远程数据库上请求的逻辑IO(老外的论文中分布式就不讨论了)

2.逻辑IO包含了 consistent gets 和 db block gets

3.IO分两种,单块顺序读,多块随机读

4.buffer cache中遵循的是LRU算法,即读入的块会放在LRU chain 的头部(MRU)端,但是全表扫描会产生一个问题,就是表太大了,把整个buffer cache都冲刷了一遍,所以在7后面的版本中全表扫的算法是把块读入LRU的尾部(LRU)端。不过如果表比较小的话,是仍然按原来的算法放在MRU端的,小的条件是小于max(2%*buffer cache,20)(注:此为11.2文档的说法),表现形式为隐含参数_SMALL_TABLE_THRESHOLD。Oracle还提供了一个手动的写法就是cache/nocache使用MRU端算法,但需要表小于CACHE_SIZE_THESHOLD参数(没找到这个参数的文档,是不是已经不用了?),否则cache是无效的。

4.优化器如何计算逻辑读与物理读呢?对于全表扫描,逻辑读=全表的块数,物理读=逻辑读/DB_FILE_MULTIBLOCK_READ_COUNT,很好算吧,但对于索引扫描(除了快速索引扫描)就不好算了,因为是单块读,不能用DB_FILE_MULTIBLOCK_READ_COUNT,所以从8.0版本开始引入了OPTIMIZER_INDEX_CACHING参数帮助计算从逻辑读到物理读的转换。计算公式变成了:

CALCULATED-LOGICAL-READS * (1 – (OPTIMIZER_INDEX_CACHING /100)) = CALCULATED-PHYSICAL-READS= COST

5. OPTIMIZER_INDEX_COST_ADJ是用来告诉oracle比较全表扫描的开销。公式如下

PREVIOUS-COST * (OPTIMIZER_INDEX_COST_ADJ/ 100) = FINAL-COST

默认值是100,也就是两者没有区别,等价

6.怎么调试OPTIMIZER_INDEX_COST_ADJ,老外给出的建议是如下语句:

SELECT sum(case whenEVENT='db file sequential read' then AVERAGE_WAIT else 0 end)*100/

       sum(case when EVENT='db file scatteredread' then AVERAGE_WAIT else 0 end) optimizer_index_cost_adj

FROM   V$SYSTEM_EVENT

7.本人的理解:从上述描述中可以看出,CBO计算开销其实不会去查看要使用的块是否已经缓存在buffer cache中,这点对于大表的全表扫描,没有太多影响,因为绝大多数情况是不缓存的,也就是逻辑读/ DB_FILE_MULTIBLOCK_READ_COUNT=物理读,而对于索引扫描计算开销有较大影响,因为块都经常缓存在buffer cache中,所以逻辑读=物理读这样的公式显然没有考虑到缓存的作用,故oracle引入了这两个参数来帮助oracle优化器的计算比较接近的开销。

 

2.      实验环境

SQL> selectversion from v$instance;

VERSION

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

11.1.0.6.0

 

SQL> showparameter optimizer_mode;

NAME                                 TYPE        VALUE

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

optimizer_mode                       string      ALL_ROWS

 

3.      实验1:CBO开销的计算与是否缓存无关

SQL> altersession set nls_language=american;

 

Session altered.

 

SQL> droptable t;

 

Table dropped.

 

SQL> createtable t as select * from dba_objects;

 

Table created.

 

SQL> createindex idx_i on t(object_id);

 

Index created.

 

SQL> altersystem flush buffer_cache;

 

System altered.

 

SQL> setautotrace on;

SQL> selectcount(1) from t where object_id<=80000;

 

  COUNT(1)

----------

     68887

 

 

Execution Plan

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

Plan hash value:3352650329

 

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

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

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

|   0 | SELECT STATEMENT      |      |     1 |    13 |   44   (3)| 00:00:01 |

|   1 | SORT AGGREGATE       |       |    1 |    13 |            |          |

|*  2 |   INDEX FAST FULL SCAN| IDX_I | 61106 |   775K|   44   (3)| 00:00:01 |

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

 

PredicateInformation (identified by operation id):

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

 

   2 - filter("OBJECT_ID"<=80000)

 

Note

-----

   - dynamic sampling used for this statement

 

 

Statistics

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

         32 recursive calls

          0 db block gets

        232 consistent gets

        977 physical reads

          0 redo size

        420 bytes sent via SQL*Net to client

        416 bytes received via SQL*Net from client

          2 SQL*Net roundtrips to/from client

          0 sorts (memory)

          0 sorts (disk)

          1 rows processed

 

SQL> selectcount(1) from t where object_id<=80000;

 

  COUNT(1)

----------

     68887

 

 

Execution Plan

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

Plan hash value:3352650329

 

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

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

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

|   0 | SELECT STATEMENT      |      |     1 |    13 |   44   (3)| 00:00:01 |

|   1 | SORT AGGREGATE       |       |    1 |    13 |            |          |

|*  2 |  INDEX FAST FULL SCAN| IDX_I | 61106 |  775K|    44   (3)| 00:00:01 |

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

 

PredicateInformation (identified by operation id):

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

 

   2 - filter("OBJECT_ID"<=80000)

 

Note

-----

   - dynamic sampling used for this statement

 

 

Statistics

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

          0 recursive calls

          0 db block gets

        160 consistent gets

          4 physical reads

          0 redo size

        420 bytes sent via SQL*Net to client

        416 bytes received via SQL*Net from client

          2 SQL*Net roundtrips to/from client

          0 sorts (memory)

          0 sorts (disk)

          1 rows processed

 

前后两次的开销都是44,没有变化。

 

实验2,使用optimizer_index_caching改变优化器计算开销

SQL> altersystem set optimizer_index_caching=0;

 

系统已更改。

 

SQL> selectobject_id from t where object_id <=40000;

 

已选择39530行。

 

 

执行计划

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

Plan hash value:2507272253

 

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

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

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

|   0 | SELECT STATEMENT     |      | 38705 |   188K|    44  (3)| 00:00:01 |

|*  1 | INDEX FAST FULL SCAN| IDX_I | 38705 |  188K|    44   (3)| 00:00:01 |

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

 

PredicateInformation (identified by operation id):

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

 

   1 - filter("OBJECT_ID"<=40000)

 

 

统计信息

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

          0 recursive calls

          0 db block gets

       2790 consistent gets

          0 physical reads

          0 redo size

     570025 bytes sent via SQL*Net to client

      29401 bytes received via SQL*Net from client

       2637 SQL*Net roundtrips to/from client

          0 sorts (memory)

          0 sorts (disk)

      39530 rows processed

 

SQL>

SQL> altersystem set optimizer_index_caching=100;

 

系统已更改。

 

SQL> selectobject_id from t where object_id <=40000;

 

已选择39530行。

 

 

执行计划

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

Plan hash value:2507272253

 

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

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

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

|   0 | SELECT STATEMENT     |      | 38705 |   188K|    44  (3)| 00:00:01 |

|*  1 | INDEX FAST FULL SCAN| IDX_I | 38705 |  188K|    44   (3)| 00:00:01 |

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

 

PredicateInformation (identified by operation id):

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

 

   1 - filter("OBJECT_ID"<=40000)

 

 

统计信息

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

          0 recursive calls

          0 db block gets

       2790 consistent gets

          0 physical reads

          0 redo size

     570025 bytes sent via SQL*Net to client

      29401 bytes received via SQL*Net from client

       2637 SQL*Net roundtrips to/from client

          0 sorts (memory)

          0 sorts (disk)

      39530 rows processed

 

通过实验我们看到,其实改变optimizer_index_caching 参数并未改变优化器对开销的计算。我回头看了下文档对optimizer_index_caching的解释发现该参数的意义,As a result, it will be more likely to picknested loops joins over hash or sort-merge joins and to pick indexes usingIN-list iterators over other indexes or full table scans. The default for thisparameter is 0, which results in default optimizer behavior.其实是优化器使用该参数之后会更加倾向于使用nested loop。下面作连接实验

SQL> altersystem set optimizer_index_caching=0;

 

系统已更改。

 

SQL> selecta.object_id

  2  fromt a,t b

  3 where a.object_id=b.object_id

  4  anda.object_id<=80000;

 

已选择68887行。

 

 

执行计划

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

Plan hash value:2093728697

 

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

 

-------

 

| Id  | Operation             | Name  | Rows | Bytes |TempSpc| Cost (%CPU)| Tim

 

e     |

 

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

 

-------

 

|   0 | SELECT STATEMENT      |      | 68887 |   672K|       |  200   (2)| 00:

 

00:03 |

 

|*  1 | HASH JOIN            |       | 68887 |   672K| 1144K|   200   (2)| 00:

 

00:03 |

 

|*  2 |  INDEX FAST FULL SCAN| IDX_I | 68887 |  336K|       |    44  (3)| 00:

 

00:01 |

 

|*  3 |  INDEX FAST FULL SCAN| IDX_I | 68887 |  336K|       |    44  (3)| 00:

 

00:01 |

 

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

 

-------

 

 

PredicateInformation (identified by operation id):

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

 

   1 -access("A"."OBJECT_ID"="B"."OBJECT_ID")

   2 -filter("A"."OBJECT_ID"<=80000)

   3 -filter("B"."OBJECT_ID"<=80000)

 

 

统计信息

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

          0 recursive calls

          0 db block gets

       4902 consistent gets

          0 physical reads

          0 redo size

    1000279 bytes sent via SQL*Net to client

      50928 bytes received via SQL*Net from client

       4594 SQL*Net roundtrips to/from client

          0 sorts (memory)

          0 sorts (disk)

      68887 rows processed

 

SQL>

SQL> altersystem set optimizer_index_caching=100;

 

系统已更改。

 

SQL> selecta.object_id

  2  fromt a,t b

  3 where a.object_id=b.object_id

  4  anda.object_id<=80000;

 

已选择68887行。

 

 

执行计划

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

Plan hash value:3970101202

 

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

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

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

|   0 | SELECT STATEMENT      |      | 68887 |   672K|    47  (9)| 00:00:01 |

|   1 | NESTED LOOPS         |       | 68887 |   672K|   47   (9)| 00:00:01 |

|*  2 |  INDEX FAST FULL SCAN| IDX_I | 68887 |  336K|    44   (3)| 00:00:01 |

|*  3 |  INDEX RANGE SCAN    | IDX_I |     1 |    5 |     0   (0)| 00:00:01 |

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

 

PredicateInformation (identified by operation id):

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

 

   2 -filter("A"."OBJECT_ID"<=80000)

   3 -access("A"."OBJECT_ID"="B"."OBJECT_ID")

       filter("B"."OBJECT_ID"<=80000)

 

 

统计信息

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

          0 recursive calls

          0 db block gets

      15131 consistent gets

          0 physical reads

          0 redo size

    1000279 bytes sent via SQL*Net to client

      50928 bytes received via SQL*Net from client

       4594 SQL*Net roundtrips to/from client

          0 sorts (memory)

          0 sorts (disk)

      68887 rows processed

 

通过修改参数后看到效果显著,使用nested loop能明显改善执行计划。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值