ORACLE优化器RBO与CBO介绍总结

RBO和CBO的基本概念 算法

 

Oracle数据库中的优化器又叫查询优化器(Query Optimizer)。它是SQL分析和执行的优化工具,它负责生成、制定SQL的执行计划。Oracle的优化器有两种,基于规则的优化器(RBO)与基于代价的优化器(CBO) 数据库

         RBO: Rule-Based Optimization 基于规则的优化器 session

         CBO: Cost-Based Optimization 基于代价的优化器 oracle

RBO自ORACLE 6以来被采用,一直沿用至ORACLE 9i. ORACLE 10g开始,ORACLE已经完全丢弃了RBO,它有着一套严格的使用规则,只要你按照它去写SQL语句,不管数据表中的内容怎样,也不会影响到你的“执行计划”,也就是说RBO对数据不“敏感”;它根据ORACLE指定的优先顺序规则,对指定的表进行执行计划的选择。好比在规则中,索引的优先级大于全表扫描;RBO是根据可用的访问路径以及访问路径等级来选择执行计划,在RBO中,SQL的写法每每会影响执行计划,它要求开发人员很是了解RBO的各项细则,菜鸟写出来的SQL脚本性能可能很是差。随着RBO的被遗弃,渐渐不为人所知。也许只有老一辈的DBA对其了解得比较深刻。关于RBO的访问路径,官方文档作了详细介绍: app

RBO Path 1: Single Row by Rowid ide

RBO Path 2: Single Row by Cluster Join 工具

RBO Path 3: Single Row by Hash Cluster Key with Unique or Primary Key 性能

RBO Path 4: Single Row by Unique or Primary Key 测试

RBO Path 5: Clustered Join 大数据

RBO Path 6: Hash Cluster Key

RBO Path 7: Indexed Cluster Key

RBO Path 8: Composite Index

RBO Path 9: Single-Column Indexes

RBO Path 10: Bounded Range Search on Indexed Columns

RBO Path 11: Unbounded Range Search on Indexed Columns

RBO Path 12: Sort Merge Join

RBO Path 13: MAX or MIN of Indexed Column

RBO Path 14: ORDER BY on Indexed Column

RBO Path 15: Full Table Scan

CBO是一种比RBO更加合理、可靠的优化器,它是从ORACLE 8中开始引入,但到ORACLE 9i 中才逐渐成熟,在ORACLE 10g中彻底取代RBO, CBO是计算各类可能“执行计划”的“代价”,即COST,从中选用COST最低的执行方案,做为实际运行方案。它依赖数据库对象的统计信息,统计信息的准确与否会影响CBO作出最优的选择。若是对一次执行SQL时发现涉及对象(表、索引等)没有被分析、统计过,那么ORACLE会采用一种叫作动态采样的技术,动态的收集表和索引上的一些数据信息。

关于RBO与CBO,我有个形象的比喻:大数据时代到来之前,作生意或许凭借多年累计下来的经验(RBO)就可以很好的作出决策,跟随市场变化。可是大数据时代,若是作生意仍是靠之前凭经验作决策,而不是靠大数据、数据分析、数据挖掘作决策,那么就有可能作出错误的决策。这也就是愈来愈多的公司对BI、数据挖掘愈来愈重视的缘故,像电商、游戏、电信等行业都已经大规模的应用,之前在一家游戏公司数据库部门作BI分析,挖掘潜在消费用户简直无所不及。至今映像颇深。

CBO与RBO的优劣

CBO优于RBO是由于RBO是一种呆板、过期的优化器,它只认规则,对数据不敏感。毕竟规则是死的,数据是变化的,这样生成的执行计划每每是不可靠的,不是最优的,CBO因为RBO能够从不少方面体现。下面请看一个例子,此案例来自于《让Oracle跑得更快》。

 
SQL> create table test as select 1 id ,object_name from dba_objects;
 
Table created.
 
SQL> create index idx_test on test(id);
 
Index created.
 
SQL> update test set id=100 where rownum =1;
 
1 row updated.
 
SQL> select id, count(1) from test group by id;
 
        ID   COUNT(1)
---------- ----------
       100          1
         1      50314

从上面能够看出,该测试表的数据分布极其不均衡,ID=100的记录只有一条,而ID=1的记录有50314条。咱们先看看RBO下两条SQL的执行计划.

SQL> select /*+ rule */ * from test where id =100;
 
 
Execution Plan
----------------------------------------------------------
Plan hash value: 2473784974
 
------------------------------------------------
| Id  | Operation                   | Name     |
------------------------------------------------
|   0 | SELECT STATEMENT            |          |
|   1 |  TABLE ACCESS BY INDEX ROWID| TEST     |
|*  2 |   INDEX RANGE SCAN          | IDX_TEST |
------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("ID"=100)
 
Note
-----
   - rule based optimizer used (consider using cbo)
 
 
Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
          3  consistent gets
          0  physical reads
          0  redo size
        588  bytes sent via SQL*Net to client
        469  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed
 
SQL> 

 

SQL> select /*+ rule */ * from test where id=1;
 
50314 rows selected.
 
 
Execution Plan
----------------------------------------------------------
Plan hash value: 2473784974
 
------------------------------------------------
| Id  | Operation                   | Name     |
------------------------------------------------
|   0 | SELECT STATEMENT            |          |
|   1 |  TABLE ACCESS BY INDEX ROWID| TEST     |
|*  2 |   INDEX RANGE SCAN          | IDX_TEST |
------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("ID"=1)
 
Note
-----
   - rule based optimizer used (consider using cbo)
 
 
Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
       7012  consistent gets
         97  physical reads
          0  redo size
    2243353  bytes sent via SQL*Net to client
      37363  bytes received via SQL*Net from client
       3356  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
      50314  rows processed

 

从执行计划能够看出,RBO的执行计划让人有点失望,对于ID=1,几乎全部的数据所有符合谓词条件,走索引只能增长额外的开销(由于ORACLE首先要访问索引数据块,在索引上找到了对应的键值,而后按照键值上的ROWID再去访问表中相应数据),既然咱们几乎要访问全部表中的数据,那么全表扫描天然是最优的选择。而RBO选择了错误的执行计划。能够对比一下CBO下SQL的执行计划,显然它对数据敏感,执行计划及时的根据数据量作了调整,当查询条件为1时,它走全表扫描;当查询条件为100时,它走区间索引扫描。以下所示:

SQL> select * from test where id=1;
 
50314 rows selected.
 
 
Execution Plan
----------------------------------------------------------
Plan hash value: 1357081020
 
--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      | 49075 |  3786K|    52   (2)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| TEST | 49075 |  3786K|    52   (2)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter("ID"=1)
 
Note
-----
   - dynamic sampling used for this statement
 
 
Statistics
----------------------------------------------------------
         32  recursive calls
          0  db block gets
       3644  consistent gets
          0  physical reads
          0  redo size
    1689175  bytes sent via SQL*Net to client
      37363  bytes received via SQL*Net from client
       3356  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
      50314  rows processed
 
SQL> select * from test where id =100;
 
 
Execution Plan
----------------------------------------------------------
Plan hash value: 2473784974
 
----------------------------------------------------------------------------------------
| Id  | Operation                   | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |          |     1 |    79 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| TEST     |     1 |    79 |     2   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | IDX_TEST |     1 |       |     1   (0)| 00:00:01 |
----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("ID"=100)
 
Note
-----
   - dynamic sampling used for this statement
 
 
Statistics
----------------------------------------------------------
          9  recursive calls
          0  db block gets
         73  consistent gets
          0  physical reads
          0  redo size
        588  bytes sent via SQL*Net to client
        469  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed
 
SQL> 

仅此一项就能够看出为何ORACLE极力推荐使用CBO,从ORACLE 10g开始不支持RBO的缘故。所谓长江后浪推前浪,前浪死在沙滩上。

CBO知识点的总结

CBO优化器根据SQL语句生成一组可能被使用的执行计划,估算出每一个执行计划的代价,并调用计划生成器(Plan Generator)生成执行计划,比较执行计划的代价,最终选择选择一个代价最小的执行计划。查询优化器由查询转换器(Query Transform)、代价估算器(Estimator)和计划生成器(Plan Generator)组成。

CBO优化器组件

CBO由如下组件构成:

· 查询转化器(Query Transformer)

查询转换器的做用就是等价改变查询语句的形式,以便产生更好的执行计划。它决定是否重写用户的查询(包括视图合并、谓词推动、非嵌套子查询/子查询反嵌套、物化视图重写),以生成更好的查询计划。

The input to the query transformer is a parsed query, which is represented by a set of
query blocks. The query blocks are nested or interrelated to each other. The form of the
query determines how the query blocks are interrelated to each other. The main
objective of the query transformer is to determine if it is advantageous to change the
form of the query so that it enables generation of a better query plan. Several different
query transformation techniques are employed by the query transformer, including:
■ View Merging
■ Predicate Pushing
■ Subquery Unnesting
■ Query Rewrite with Materialized Views
Any combination of these transformations can be applied to a given query.

· 代价评估器(Estimator)

评估器经过复杂的算法结合来统计信息的三个值来评估各个执行计划的整体成本:选择性(Selectivity)、基数(Cardinality)、成本(Cost)

计划生成器会考虑可能的访问路径(Access Path)、关联方法和关联顺序,生成不一样的执行计划,让查询优化器从这些计划中选择出执行代价最小的一个计划。

· 计划生成器(Plan Generator)

计划生成器就是生成大量的执行计划,而后选择其整体代价或整体成本最低的一个执行计划。

因为不一样的访问路径、链接方式和链接顺序能够组合,虽然以不一样的方式访问和处理数据,可是能够产生一样的结果

clip_image001

下图是我本身为了加深理解,用工具画的图

clip_image002

 

查看ORACLE优化器

SQL> show parameter optimizer_mode;
 
NAME                           TYPE        VALUE
--------------------------- ----------- -----------------
optimizer_mode                 string      ALL_ROWS

clip_image003

 

修改ORACLE优化器

ORACLE 10g 优化器能够从系统级别、会话级别、语句级别三种方式修改优化器模式,很是方便灵活。

其中optimizer_mode能够选择的值有: first_rows_n,all_rows.  其中first_rows_n又有first_rows_1000, first_rows_100, first_rows_10, first_rows_1

在Oracle 9i中,优化器模式能够选择first_rows_n,all_rows, choose, rule 等模式:

 

Rule: 基于规则的方式。

Choolse:指的是当一个表或或索引有统计信息,则走CBO的方式,若是表或索引没统计信息,表又不是特别的小,并且相应的列有索引时,那么就走索引,走RBO的方式。

If OPTIMIZER_MODE=CHOOSE, if statistics do not exist, and if you do not add hints to SQL statements, then SQL statements use the RBO. You can use the RBO to access both relational data and object types. If OPTIMIZER_MODE=FIRST_ROWS, FIRST_ROWS_n, or ALL_ROWS and no statistics exist, then the CBO uses default statistics. Migrate existing applications to use the cost-based approach.

First Rows:它与Choose方式是相似的,所不一样的是当一个表有统计信息时,它将是以最快的方式返回查询的最早的几行,从整体上减小了响应时间。

All Rows: 10g中的默认值,也就是咱们所说的Cost的方式,当一个表有统计信息时,它将以最快的方式返回表的全部的行,从整体上提升查询的吞吐

虽然Oracle 10g中再也不支持RBO,Oracle 10g官方文档关于optimizer_mode参数的只有first_rows和all_rows.可是依然能够设置 optimizer_mode为rule或choose,估计是ORACLE为了过渡或向下兼容考虑。以下所示。

 

系统级别

SQL> alter system set optimizer_mode=rule scope=both;
 
System altered.
 
SQL> show parameter optimizer_mode
 
NAME                                 TYPE        VALUE
-------------------------------- ----------- -----------------------
optimizer_mode                       string      RULE

clip_image004

 

 

会话级别

会话级别修改优化器模式,只对当前会话有效,其它会话依然使用系统优化器模式。

SQL> alter session set optimizer_mode=first_rows_100;

Session altered.

 

语句级别

语句级别经过使用提示hints来实现。

SQL> select /*+ rule */ * from dba_objects where rownum <= 10;

相关文章
相关标签/搜索