Oracle的优化器有两种优化方式(一)

Oracle的优化器有两种优化方式(整理), 2010-04-13
RBO方式:基于规则的优化方式(Rule-Based Optimization,简称为RBO)
  优化器在分析SQL语句时,所遵循的是Oracle内部预定的一些规则。比如我们常见的,当一个where子句中的一列有索引时去走索引。


CBO方式基于代价的优化方式(Cost-Based Optimization,简称为CBO)
它是看语句的代价(Cost),这里的代价主要指Cpu和内存。优化器在判断是否用这种方式时,主要参照的是表及索引的统计信息。统计信息给出表的大小、有少行、每行的长度等信息。这些统计信息起初在库内是没有的,是做analyze后才出现的,很多时候过期统计信息会令优化器做出一个错误的执行计划,因此应及时更新这些信息。

 

所以hint也不例外,除了/*+rule*/其他的都是CBO优化方式
优化模式包括Rule、Choose、First rows、All rows四种方式

Rule:基于规则的方式。
Choose:默认的情况下Oracle用的便是这种方式。指的是当一个表或索引有统计信息,则走CBO的方式,如果表或索引没统计信息,表又不是特别的小,而且相应的列有索引时,那么就走索引,走RBO的方式。

PS: 优化模式是CHOOSE的情况下,看Cost参数是否有值来决定采用CBO还是RBO:
SELECT STATEMENT [CHOOSE] Cost=1234 --Cost有值,采用CBO
SELECT STATEMENT [CHOOSE] Cost=    --Cost为空,采用RBO

PS的信息是从另外篇帖子里看到的,COST有值应该是指“有统计信息”的含义,暂时如此理解.
 First Rows:它与Choose方式是类似的,所不同的是当一个表有统计信息时,它将是以最快的方式返回查询的最先的几行,从总体上减少了响应时间。 
All Rows:也就是我们所说的Cost的方式,当一个表有统计信息时,它将以最快的方式返回表的所有的行,从总体上提高查询的吞吐量。没有统计信息则走RBO的方式

 

Oracle如何配置默认的优化规则 
A、Instance级别我们可以通过在initSID.ora文件中设定OPTIMIZER_MODE=RULE/CHOOSE/FIRST_ROWS/ALL_ROWS如果没设定OPTIMIZER_MODE参数则默认用的是Choose方式。

B、Sessions级别通过ALTER SESSION SET OPTIMIZER_MODE=RULE/CHOOSE/FIRST_ROWS/ALL_ROWS来设定.

C、语句级别用Hint(/*+ ... */)来设定 
为什么表的某个字段明明有索引,但执行计划却不走索引? 
    1、优化模式是all_rows的方式 
    2、表作过analyze,有统计信息 
    3、表很小,Oracle的优化器认为不值得走索引。


优化器提示 :不区分大小写, 多个提示用空格分开 
如:select /*+ hint1(tab1) hint2(TAB1 idx1) */ col1, col2 from tab1 where col1='xxx'; 
如果表使用了别名, 那么提示里也必须使用别名 
如:select /*+ hint1(t1) */ col1, col2 from tab1 t1 where col1='xxx'; 
如果使用同一个表的多个用,号分开 
如: select /*+ index(t1.A,t1.B) */ col1, col2  from   tab1 t1 where  col1='xxx';

 

 

 

没有使用HINT的执行计划如下:

SELECT  EMPNO,ENAME,SAL FROM EMP WHERE EMPNO=7788;

Execution Plan

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

   0      SELECT STATEMENT Optimizer=CHOOSE

   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'EMP'

   2    1     INDEX (UNIQUE SCAN) OF 'PK_EMP' (UNIQUE)

 

1. /*+ALL_ROWS*/ 
表明对语句块选择基于开销的优化方法,并获得最佳吞吐量,使资源消耗最小化. 
SELECT /*+ALL+_ROWS*/ EMPNO,ENAME,SAL FROM EMP WHERE EMPNO=7788;

Execution Plan

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

   0      SELECT STATEMENT Optimizer=CHOOSE

   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'EMP'

   2    1     INDEX (UNIQUE SCAN) OF 'PK_EMP' (UNIQUE)

2. /*+FIRST_ROWS*/ 
表明对语句块选择基于开销的优化方法,并获得最佳响应时间,使资源消耗最小化. 
SELECT /*+FIRST_ROWS*/ EMPNO,ENAME,SAL FROM EMP WHERE EMPNO=7788;
Execution Plan

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

 0       SELECT STATEMENT Optimizer=HINT: FIRST_ROWS (Cost=1 Card=1 Bytes=33)

 1    0  TABLE ACCESS (BY INDEX ROWID) OF 'EMP' (Cost=1 Card=1 Bytes=33)

 2    1  INDEX (RANGE SCAN) OF 'PK_EMP' (UNIQUE) (Cost=1 Card=1)


3. /*+CHOOSE*/ 
表明如果数据字典中有访问表的统计信息,将基于开销的优化方法,并获得最佳的吞吐量;如果数据字典中没有访问表的统计信息,将基于规则开销的优化方法; 
SELECT /*+CHOOSE*/ EMPNO,ENAME,SAL FROM EMP WHERE EMPNO=7788;

Execution Plan

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

   0      SELECT STATEMENT Optimizer=HINT: CHOOSE

   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'EMP'

   2    1     INDEX (UNIQUE SCAN) OF 'PK_EMP' (UNIQUE)

4. /*+RULE*/ 
表明对语句块选择基于规则的优化方法. 
SELECT /*+ RULE */ EMPNO,ENAME,SAL FROM EMP WHERE EMPNO=7788; 
Execution Plan

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

   0      SELECT STATEMENT Optimizer=HINT: RULE

   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'EMP'

   2    1     INDEX (UNIQUE SCAN) OF 'PK_EMP' (UNIQUE)
5. /*+FULL(TABLE)*/ 
表明对表选择全局扫描的方法. 
SELECT /*+FULL(E)*/  EMPNO,ENAME,SAL FROM EMP E WHERE EMPNO=7788;

Execution Plan

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

   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=1 Bytes=33)

   1    0   TABLE ACCESS (FULL) OF 'EMP' (Cost=2 Card=1 Bytes=33)


6. /*+ROWID(TABLE)*/ 
提示明确表明对指定表根据ROWID进行访问. 
SELECT /*+ROWID(BSEMPMS)*/ * FROM EMP WHERE ROWID>=' AAAHW7AABAAAMUiAAH'  AND EMPNO=7788; 
Execution Plan

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

   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=1 Card=1 Bytes=94)

   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'EMP' (Cost=1 Card=1 Byte s=94)

   2    1     INDEX (RANGE SCAN) OF 'PK_EMP' (UNIQUE) (Cost=1 Card=1)


7. /*+CLUSTER(TABLE)*/ (可能没有簇对象,暂且还没有使用和理解簇对象)
提示明确表明对指定表选择簇扫描的访问方法,它只对簇对象有效. 
select /*+CLUSTER */ e.empno ,d.dname from emp e,dept d  where e.deptno=d.deptno;

Execution Plan

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

   0      SELECT STATEMENT Optimizer=CHOOSE

   1    0   NESTED LOOPS

   2    1     TABLE ACCESS (FULL) OF 'EMP'

   3    1     TABLE ACCESS (BY INDEX ROWID) OF 'DEPT'

   4    3       INDEX (UNIQUE SCAN) OF 'PK_DEPT' (UNIQUE)

8. /*+INDEX(TABLE INDEX_NAME)*/ 
表明对表选择索引的扫描方法. 指定使用表的某个索引:

我在EMP表建立HIREDATE索引create index emp_date_idx on emp(hiredate);

SQL> select * from emp e where e.hiredate=to_date('1987-04-19','yyyy-mm-dd') and e.empno=7788;

Execution Plan

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

   0      SELECT STATEMENT Optimizer=CHOOSE

   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'EMP'

   2    1     INDEX (UNIQUE SCAN) OF 'PK_EMP' (UNIQUE)

上面的查询语句同时使用了主键索引和日期索引,但是执行计划里并没有使用我建立日期的索引,因为采用基于效率的CBO模式,用EMPNOUNIQUE索引效率高,下面强制使用日期索引进行查询得到的执行计划如下:

SQL>select  /*+INDEX(emp emp_date_idx)*/  *  from emp e

where e.hiredate=to_date('1987-04-19','yyyy-mm-dd') and e.empno=7788;

 

Execution Plan

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

   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=1 Card=1 Bytes=87)

   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'EMP' (Cost=1 Card=1 Bytes=87)

   2    1     INDEX (RANGE SCAN) OF 'EMP_DATE_IDX' (NON-UNIQUE) (Cost=1 Card=1)

9. /*+INDEX_ASC(TABLE INDEX_NAME)*/ 
表明对表选择索引升序的扫描方法. (相当于ORDER BY 索引列 ASC)
SQL> SELECT  /*+INDEX_ASC(emp PK_EMP)*/  *  FROM  EMP;

Execution Plan

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

   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=826 Card=82 Bytes=7134)

   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'EMP' (Cost=826 Card=82 Bytes=7134)

   2    1     INDEX (FULL SCAN) OF 'PK_EMP' (UNIQUE) (Cost=26 Card=82)

对比下执行计划  

SQL> select * from emp order by empno;(基于RBO的模式,理解有误?)

Execution Plan

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

   0      SELECT STATEMENT Optimizer=CHOOSE

   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'EMP'

   2    1     INDEX (FULL SCAN) OF 'PK_EMP' (UNIQUE)

10. /*+INDEX_COMBINE*/ 
为指定表选择位图访问路经,如果INDEX_COMBINE中没有提供作为参数的索引,将选择出位图索引的布尔组合方式. (位图索引搁置….)


11. /*+INDEX_JOIN(TABLE INDEX_NAME)*/ 
提示明确命令优化器使用索引作为访问路径. 
SQL>SELECT /*+INDEX_JOIN(EMP EMP_DATE_IDX)*/  SAL,HIREDATE FROM EMP E

where e.hiredate>to_date('1980-04-19','yyyy-mm-dd');

Execution Plan

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

   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=1 Card=4 Bytes=88)

   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'EMP' (Cost=1 Card=4 Bytes=88)

   2    1     INDEX (RANGE SCAN) OF 'EMP_DATE_IDX' (NON-UNIQUE) (Cost=2 Card=1)

12. /*+INDEX_DESC(TABLE INDEX_NAME)*/ 
表明对表选择索引降序的扫描方法. (9)

13. /*+INDEX_FFS(TABLE INDEX_NAME)*/ 
对指定的表执行快速全索引扫描,而不是全表扫描的办法. 
select /*+index_ffs(emp pk_emp)*/ * from emp where empno=7788;

14. /*+ADD_EQUAL TABLE INDEX_NAM1,INDEX_NAM2,...*/ 
提示明确进行执行规划的选择,将几个单列索引的扫描合起来. 
select /*+index_ffs(emp pk_emp emp_date_idx)*/ * from emp e where empno=7788 and e.hiredate=to_date('1987-04-19','yyyy-mm-dd');

15. /*+USE_CONCAT*/ 
对查询中的WHERE后面的OR条件进行转换为UNION  ALL的组合查询. (懵懂啊,先存着)
例如: 
select /*+use_concat */ * from emp where deptno=10 OR empno=7788;

Execution Plan

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

   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=2 Bytes=174)

   1    0   TABLE ACCESS (FULL) OF 'EMP' (Cost=2 Card=2 Bytes=174)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值