Oracle的优化器有两种优化方式
2024-03-04
[摘要] RBO方式:基于规则的优化方式(Rule-BasedOptimization,简称为RBO)?优化器在分析SQL语句时,所遵循的是Oracle内部预定的一些规则。比如我们常见的,当一个where子句中的一列有索引时去走索引。CBO方式:基于代价的优化方式(Cost-BasedOptimization,简称为CBO)它是看语句的代

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


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

?

所以hint也不例外,除了其他的都是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 col1, col2 from tab1 where col1='xxx';
如果表使用了别名, 那么提示里也必须使用别名
如:select col1, col2 from tab1 t1 where col1='xxx';
如果使用同一个表的多个用,号分开
如: select 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.
表明对语句块选择基于开销的优化方法,并获得最佳吞吐量,使资源消耗最小化.
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)

2.
表明对语句块选择基于开销的优化方法,并获得最佳响应时间,使资源消耗最小化.
SELECT 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.
表明如果数据字典中有访问表的统计信息,将基于开销的优化方法,并获得最佳的吞吐量;如果数据字典中没有访问表的统计信息,将基于规则开销的优化方法;
SELECT 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.
表明对语句块选择基于规则的优化方法.
SELECT 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.
表明对表选择全局扫描的方法.
SELECT ?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进行访问.
SELECT * 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. (可能没有簇对象,暂且还没有使用和理解簇对象)
提示明确表明对指定表选择簇扫描的访问方法,它只对簇对象有效.
select 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.
表明对表选择索引的扫描方法. 指定使用表的某个索引:

我在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 ? ?* ?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.
表明对表选择索引升序的扫描方法. (相当于ORDER BY 索引列 ASC)
SQL> SELECT? ?* ?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中没有提供作为参数的索引,将选择出位图索引的布尔组合方式. (位图索引搁置….)


11.
提示明确命令优化器使用索引作为访问路径.
SQL>SELECT ? 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.
表明对表选择索引降序的扫描方法. (9)

13.
对指定的表执行快速全索引扫描,而不是全表扫描的办法.
select * from emp where empno=7788;

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

15.
对查询中的WHERE后面的OR条件进行转换为UNION ?ALL的组合查询. (懵懂啊,先存着)
例如:
select * 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)


平台注册入口