最后我们介绍几个可能影响到Optimizer的系统参数。
7、优化参数5——optimizer_index_caching
参数optimizer_index_caching的含义在于一个估算值,就是告诉优化器当进行索引路径检索的时候,特别是nested loop连接时索引探知(index probe)的成本。该参数的取值范围是0-100,描述使用索引的时候,索引在buffer cache中的比例。这个参数的选取会影响到nested loop和in-list循环的成本估算值。
默认情况下,Oracle这个参数取值为0。
SQL> show parameter optimizer_index_cach
NAME TYPE VALUE
------------------------------------ ----------- --------------------------
optimizer_index_caching integer 0
如果这个取值设置为100,就表示在使用索引路径的时候,所检索的索引块在buffer cache中都已经缓存住。注意,这个参数只是一个估计值,是我们进行控制成本公式使用的。真正在运行的时候,索引块在buffer cache中的比例是不能预知的!!
显而易见,在控制这个参数的前提下,Oracle在计算索引路径执行计划的时候,成本值就自然有所降低。进而,最后CBO选择出的执行计划就更加倾向于索引路径和Nested Loop连接方式。
我们通过下面简单的实验去验证。我们首先看看非连接条件下的索引路径成本计算,选取上面参数实验t_obj和t_tables作为实验环境。
--补充索引构建
SQL> create index idx_t_obj_owner on t_obj(owner);
Index created
SQL> exec dbms_stats.gather_table_stats(user,'T_OBJ',cascade => true);
PL/SQL procedure successfully completed
分别在optimizer_index_caching两个极端情况下进行试验。
--在取值为0的时候进行试验;
SQL> alter session set optimizer_index_caching=0;
Session altered
SQL> explain plan for select * from t_obj where wner='SCOTT';
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------
Plan hash value: 2947685431
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%C
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 25 | 2325 | 2
| 1 | TABLE ACCESS BY INDEX ROWID| T_OBJ | 25 | 2325 | 2
|* 2 | INDEX RANGE SCAN | IDX_T_OBJ_OWNER | 25 | | 1
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("OWNER"='SCOTT')
14 rows selected
--修改参数
SQL> alter session set optimizer_index_caching=100;
Session altered
SQL> select value from v$parameter where name='optimizer_index_caching';
VALUE
-------------------------------
100
SQL> explain plan for select * from t_obj where wner='SCOTT';
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------
Plan hash value: 2947685431
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%C
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 25 | 2325 | 2
| 1 | TABLE ACCESS BY INDEX ROWID| T_OBJ | 25 | 2325 | 2
|* 2 | INDEX RANGE SCAN | IDX_T_OBJ_OWNER | 25 | | 1
-----------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("OWNER"='SCOTT')
14 rows selected
虽然都是进行索引路径,但是对最后成本值影响不大。究其原因,可能是笔者选择的选择率过小的原因。
下面实验nested loop路径成本情况。
SQL> alter session set optimizer_index_caching=0;
Session altered
SQL> explain plan for select /*+ use_nl(a, b)*/* from t_obj a, t_tables b where a.owner=b.owner and a.object_name=b.table_name;
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------
Plan hash value: 2368859676
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1606 | 467K| 3229 (1
| 1 | TABLE ACCESS BY INDEX ROWID| T_OBJ | 1 | 93 | 2 (0
| 2 | NESTED LOOPS | | 1606 | 467K| 3229 (1
| 3 | TABLE ACCESS FULL | T_TABLES | 1606 | 321K| 12 (0
|* 4 | INDEX RANGE SCAN | IDX_T_OBJ_CMP | 1 | | 1 (0
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("A"."OWNER"="B"."OWNER" AND "A"."OBJECT_NAME"="B"."TABLE_NAME")
16 rows selected
当进行强制的nested loop路径选择之后,我们在index_caching参数为0的时候,成本为3229,主要消耗在进行nested loop连接路径上。那么,当我们修改为100时,执行计划如何变化呢?
SQL> alter session set optimizer_index_caching=100;
Session altered
SQL> explain plan for select /*+ use_nl(a, b)*/* from t_obj a, t_tables b where a.owner=b.owner and a.object_name=b.table_name;
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------
Plan hash value: 709597304
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1606 | 467K| 789
| 1 | TABLE ACCESS BY INDEX ROWID| T_TABLES | 1 | 205 | 1
| 2 | NESTED LOOPS | | 1606 | 467K| 789
| 3 | TABLE ACCESS FULL | T_OBJ | 50387 | 4576K| 157
|* 4 | INDEX RANGE SCAN | IDX_T_TABLES_CMP | 1 | | 0
------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("A"."OWNER"="B"."OWNER" AND "A"."OBJECT_NAME"="B"."TABLE_NAME")
16 rows selected
效果非常明显,成本值只有789。说明该参数在成本路径计算中的作用和分量。但是,再次强调:参数只是控制和影响CBO进行决策的手段,它们只能影响到最后执行计划的决策选择,真正的执行时间还要看实际的环境和数据情况而定。
8、优化参数6——optimizer_index_cost_adj
该参数也是用来调整索引路径成本的。简单的说,optimizer_index_cost_adj参数就是索引路径偏好的“缩放灯”。参数取值范围为0-10000,默认为100。
SQL> show parameter optimizer_index_cost
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
optimizer_index_cost_adj integer 100
当Oracle依据统计量(数据表、索引对象)计算出index access路径成本之后,会根据这个参数进行一定比例的放大和缩小。例如,如果该参数设置为10,表示会对索引路径执行计划的成本进行10%的缩小。
应用该参数,我们可以控制索引路径的偏好度,放大或者缩小CBO成本计算公式中索引路径成本的计算值。进而控制实际选择出的执行计划。
下面我们根据实验来体会效果,我们同样适用两个SQL语句在三个参数取值下的情况进行实验。
首先,我们选择默认的optimizer_index_cost_adj取值下的情况。
SQL> select value from v$parameter where name='optimizer_index_cost_adj';
VALUE
------------------------------
100
SQL> explain plan for select * from t_obj where wner='SYS';
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------
Plan hash value: 172510092
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 22351 | 2029K| 156 (2)| 00:00:02 |
|* 1 | TABLE ACCESS FULL| T_OBJ | 22351 | 2029K| 156 (2)| 00:00:02 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("OWNER"='SYS')
13 rows selected
SQL> explain plan for select * from t_obj where wner='SCOTT';
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------
Plan hash value: 2947685431
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%C
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 25 | 2325 | 2
| 1 | TABLE ACCESS BY INDEX ROWID| T_OBJ | 25 | 2325 | 2
|* 2 | INDEX RANGE SCAN | IDX_T_OBJ_OWNER | 25 | | 1
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("OWNER"='SCOTT')
14 rows selected
下面,我们缩小参数值到10,也就是缩小索引路径成本到原来的10%。
SQL> alter session set optimizer_index_cost_adj=10;
Session altered
SQL> explain plan for select * from t_obj where wner='SYS';
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------
Plan hash value: 2947685431
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%C
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 22351 | 2029K| 65
| 1 | TABLE ACCESS BY INDEX ROWID| T_OBJ | 22351 | 2029K| 65
|* 2 | INDEX RANGE SCAN | IDX_T_OBJ_OWNER | 22351 | | 5
------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("OWNER"='SYS')
14 rows selected
SQL> explain plan for select * from t_obj where wner='SCOTT';
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------
Plan hash value: 2947685431
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%C
------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 25 | 2325 | 1
| 1 | TABLE ACCESS BY INDEX ROWID| T_OBJ | 25 | 2325 | 1
|* 2 | INDEX RANGE SCAN | IDX_T_OBJ_OWNER | 25 | | 1
-----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("OWNER"='SCOTT')
14 rows selected
我们看到了实验现象:对owner=’SYS’而言,当不进行索引路径成本缩放的时候索引路径的成本是要高于全表扫描FTS的,所以CBO选择了FTS作为路径计算。但是,当我们将参数设置为10,也就是进行10%比例的缩放时,索引路径的成本就下降到了65,小于FTS的156成本值。结果CBO在这种情况下选择了索引路径。
当owner=’SCOTT’语句中,成本也有一定程度的降低。因为取值本身就很小了,所以减小效果不明显。
下面我们将参数调节到另一个极端,参数放大到10000。
SQL> alter session set optimizer_index_cost_adj=10000;
Session altered
SQL> explain plan for select * from t_obj where wner='SYS';
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------
Plan hash value: 172510092
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 22351 | 2029K| 156 (2)| 00:00:02 |
|* 1 | TABLE ACCESS FULL| T_OBJ | 22351 | 2029K| 156 (2)| 00:00:02 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("OWNER"='SYS')
13 rows selected
--强制的索引路径;
SQL> explain plan for select /*+ index(t_obj IDX_T_OBJ_OWNER)*/* from t_obj where wner='SYS';
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 2947685431
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%C
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 22351 | 2029K| 64906
| 1 | TABLE ACCESS BY INDEX ROWID| T_OBJ | 22351 | 2029K| 64906
|* 2 | INDEX RANGE SCAN | IDX_T_OBJ_OWNER | 22351 | | 5283
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("OWNER"='SYS')
14 rows selected
上面的实验中,我们将索引路径的成本放大了100倍。原有的owner=’SYS’语句重新选择了FTS路径。如果我们强迫它去走索引路径,结果成本计算出的64906,恰恰是之前650成本值的近100倍。
那么,owner=’SCOTT’结果情况如何呢?
SQL> explain plan for select * from t_obj where wner='SCOTT';
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------
Plan hash value: 172510092
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 25 | 2325 | 156 (2)| 00:00:02 |
|* 1 | TABLE ACCESS FULL| T_OBJ | 25 | 2325 | 156 (2)| 00:00:02 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("OWNER"='SCOTT')
13 rows selected
owner=’SCOTT’选择率极低,但是在放大100倍的效应下,CBO也放弃了索引路径,选择了FTS作为最终执行计划。
9、结论
Oracle Optimizer本质上,就是一系列计算公式比较。我们提供数据对象的统计量,外加适当的参数作为引导,最后可以帮助CBO去生成更好的执行计划。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/17203031/viewspace-720953/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/17203031/viewspace-720953/