日期:2014-05-16  浏览次数:20466 次

Oracle优化器参考(新整理)(转)
Oracle优化器参考(新整理)

                                      

      本文讲述了Oracle优化器的概念、工作原理和使用方法,兼顾了Oracle8i、9i以及最新的10g三个版本。理解本文将有助于您更好的更有效的进行SQL优化工作。

RBO优化器

      RBO是一种基于规则的优化器,随着CBO优化器的逐步发展和完善,在最新的10g版本中Oracle已经彻底废除了RBO。正在使用Oracle8i或9i的人们或多或少的都会碰到RBO,因此在详细介绍CBO之前,我们有必要简单回顾一下古老的RBO优化器。
      在RBO中Oracle根据可用的访问路径和访问路径的等级来选择执行计划,等级越高的访问路径通常运行SQL越慢,如果一个语句有多个路径可走,Oracle总是选择等级较低的访问路径。

RBO访问路径

1级:用Rowid定位单行
      当WHERE子句中直接嵌入Rowid时,RBO走此路径。Oracle不推荐直接引用Rowid,Rowid可能会由于版本的改变而变化,行迁移、行链接、EXP/IMP也会使Rowid发生变化。
2级:用Cluster Join定位单行
      两个表做等值连接,一方的连接字段是Cluster Key,且WHERE中存在可以保证该语句仅返回一行记录的条件时,RBO走此路径。
3级:用带用唯一约束或做主键的Hash Cluster Key定位单行
4级:用唯一约束的字段或做主键的字段来定位单行
5级:Cluster Join
6级:使用Hash Cluster Key
7级:使用索引Cluster Key
8级:使用复合索引
9级:使用单字段索引
10级:用索引进行有界限范围的查找
     如,column >[=] expr AND column <[=] expr或column BETWEEN expr AND expr
或column LIKE ‘c%’
11级:用索引字段进行无界限的查找
     如,WHERE column >[=] expr 或 WHERE column <[=] expr
12级:排序合并连接
13级:对索引字段使用MAX或MIN函数
14级:ORDER BY索引字段
15级:全表扫描
      如果可以使用索引RBO会尽可能的去用索引而不是全表扫描,但是在下列一些情况RBO只能使用全表扫描:
     如果column1和column2是同一个表的字段,含有条件column1 < column2或column1 > column2或column1 <= column2或column1 >= column2,RBO会用全表扫描。
     如果使用column IS NULL或column IS NOT NULL或column NOT IN或column != expr或column LIKE ‘%ABC’时,不论column有无索引,RBO都使用全表扫描。
     如果expr = expr2,expr表达式作用了一个字段上,无论该字段有无索引,RBO都会全表扫描。
NOT EXISTS子查询以及在视图中使用ROWNUM也会造成RBO进行全表扫描。
     以上就是RBO的全部可用访问路径。RBO优化器死板的根据规则来选择执行计划显然不够灵活,在RBO中也无法使用物化视图等Oracle提供的新特性,在Oracle8i时CBO已经基本成熟,因此Oracle强烈建议改用CBO优化器。下文将全面介绍CBO优化器。

CBO优化器结构

      CBO是基于成本的优化器,它根据可用的访问路径、对象的统计信息、嵌入的Hints来选择一个成本最低的执行计划。

CBO主要包含以下组件:

l 查询转换器(Query Transformer)
l 评估器(Estimator)
l 计划生成器(Plan Generator)

查询转换器

      查询语句的形式会影响所产生的执行计划,查询转换器的作用就是改变查询语句的形式以产生较好的执行计划。
     从Oracle 8i开始就有四种转换技术:视图合并(View Merging)、谓词推进(Predicate Pushing)、非嵌套子查询(Subquery Unnesting)和物化视图的查询重写(Query Rewrite with Materialized Views)。
      视图合并:如果SQL语句中含有视图,经分析后会把视图放在独立的“视图查询块”中,每个视图会产生一个视图子计划,当为整个语句产生执行计划时,视图子计划会被直接拿来使用而不会照顾到语句的整体性,这样就很容易导致不良执行计划的生成。视图合并就是为了去掉“视图查询块”,将视图合并到一个整体的查询块中,这样就不会有视图子计划产生,执行计划的优良性得到提升。
      谓词推进:不是所有的视图都能够被合并,对于那些不能被合并的视图Oracle会将相应的谓词推进到视图查询块中,这些谓词通常是可索引的或者是过滤性较强的。
      非嵌套子查询:子查询和视图一样也是被放于独立查询块中的,查询转换器会将绝大多数子查询转换为连接从而合并为同一查询块,少量不能被转换为连接的子查询,会将它们的子计划安照一个高效的方式排列。
      物化视图的查询重写:当query_rewrite_enabled=true时,查询转换器寻找与该查询语句相关联的物化视图,并用物化视图改写该查询语句。

关于“窥视”(Peeking)

      在Oracle9i中为查询转换器增加了一个功能,就是当用户使用绑定变量时,查询转换器可以“偷窥”绑定变量的实际值。
      我们知道使用绑定变量虽然可以有效的减少“硬分析”,但它带来的负面影响是优化器无法根据实际的数据分布来优化SQL,很有可能本可以走索引的SQL却做了全表扫描。“窥视”正是为了解决这个问题,但是它并没有彻底的解决,Oracle只允许第一次调用时进行“窥视”,接下来的调用即使绑定变量的值发生了变化,也仍然是使用第一次生成的执行计划,这就造成了一个错误的执行计划会被多次使用,10g中的“窥视”也是如此。

评估器

      评估器通过计算三个值来评估计划的总体成本:选择性(Selectivity)、基数(Cardinality)、成本(Cost)。
     选择性:是一个大于0小于1的数,0表示没有记录被选定,1表示所有记录都被选定。统计信息和直方图关系到选择性值的准确性。如:name=’Davis’,如果不存