测试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之间.该参数表示索引扫描和全表扫描成本的比较。

    在基于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 readdb 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
NAME                                 TYPE        VALUE
------------------------------------ ----------- -----
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   (0)| 00:00:02 |
|*  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';
Execution Plan
----------------------------------------------------------
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 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter("OWNER"='HR')
Note
-----
   - dynamic sampling used for this statement (level=2)

默认的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


SQL> set autotrace traceonly explain;
SQL> select * from t where owner='HR';


Execution Plan
----------------------------------------------------------
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 |
--------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

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

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

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

原来: 在比较的时候,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)


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

SQL> ALTER SESSION SET OPTIMIZER_INDEX_COST_ADJ=1725;
Session altered.


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|  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 |


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

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("OWNER"='HR')
Note
-----
   - dynamic sampling used for this statement (level=2)

果然,此时又走的索引,但是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

相关文章
|
12月前
|
存储 SQL JSON
MySQL optimizer_trace cost量化分析
MySQL optimizer_trace cost量化分析
128 0
|
SQL 架构师 关系型数据库
不可置信!SQL 优化终于干掉了“distinct”
sql 优化之多表联合查询干掉 “distinct” 去重关键字 在我提交了代码的时候,架构师给我指出我这个sql这样写会有问题。因为在分库分表的时候,是不支持子查询的。 所以需要把多表的子查询的 sql 结构进行优化。 是不是挺恐怖的;(此处为了脱敏,我把相关的 sql 关键词都给打码掉了)
|
SQL Oracle 关系型数据库
【SQL开发实战技巧】系列(十五):查找最值所在行数据信息及快速计算总和百之max/min() keep() over()、fisrt_value、last_value、ratio_to_report
本篇文章讲解的主要内容是:***计算部门中那个工资等级的员工最多、通过返回部门10最大工资所在行的员工名称小案例来讲解max/min() keep() over()、通过查询工资最高的人小案例来介绍fisrt_value、last_value、通过计算各个部门的工资合计以及各个部门合计工资占总工资的比例小案例来介绍如何计算百分比及ratio_to_report分析函数的使用***
【SQL开发实战技巧】系列(十五):查找最值所在行数据信息及快速计算总和百之max/min() keep() over()、fisrt_value、last_value、ratio_to_report
|
人工智能 分布式计算 前端开发
更高效的Cascades优化器 - Columbia Query Optimizer
在较早的文章中介绍了些Volcano/Cascades优化器框架的设计理念和实现思路,基本是基于论文的解读:VolcanoCascades虽然cascades号称目前最为先进的优化器搜索框架,但不得不说这2篇paper的内容,实在是让人看起来有些吃力。尤其是后篇,说是从工程实现的角度来描述,但讲解的不够详尽,而且有些地方既模糊又抽象。此外工业界并没有一款优化器是完全基于paper的框架去实现的,这
1504 0
更高效的Cascades优化器 - Columbia Query Optimizer
|
存储 关系型数据库 Go
PostgreSQL 11 内核优化 - 降低vacuum cleanup阶段index scan概率 ( vacuum_cleanup_index_scale_factor , skip index vacuum cleanup stage)
PostgreSQL 11 内核优化 - 降低vacuum cleanup阶段index scan概率 ( vacuum_cleanup_index_scale_factor , skip index vacuum cleanup stage)
1224 0
|
SQL Oracle 关系型数据库
PostgreSQL JOIN limit 优化器 成本计算 改进 - mergejoin startup cost 优化
标签 PostgreSQL , join , limit , startup cost , cbo , 优化器改进 背景 PostgreSQL limit N的成本估算,是通过计算总成本A,以及估算得到的总记录数B得到: (N/B)*A 大概意思就是占比的方法计算 对于单表查询...
1169 0
|
存储 SQL 关系型数据库
MySQL8.0 · 优化器新特性 · Cost Model, 直方图及优化器开销优化
MySQL当前已经发布到MySQL8.0版本,在新的版本中,可以看到MySQL之前被人诟病的优化器部分做了很多的改动,由于笔者之前的工作环境是5.6,最近切换到最新的8.0版本,本文涵盖了一些本人感兴趣的和优化器相关的部分,主要包括MySQL5.7的cost model以及MySQL8.0的直方图功能。
3059 0
|
SQL 移动开发 Oracle
optimizer_index_caching和optimizer_index_cost_adj两个参数说明
optimizer_index_caching和optimizer_index_cost_adj两个参数说明 OPTIMIZER_INDEX_COST_ADJ Property ...
1581 0