ITPub博客

首页 > 数据库 > Oracle > What the RBO rules don't tell you

What the RBO rules don't tell you

原创 Oracle 作者:sunwgneuqsoft 时间:2007-12-01 09:42:46 0 删除 编辑

前言

下面的20条就是RBO的优化规则:

Rank Condition

1 ROWID = constant

2 Cluster join with unique or primary key = constant

3 Hash cluster key with unique or primary key = constant

4 Entire Unique concatenated index = constant

5 Unique indexed column = constant

6 Entire cluster key = corresponding cluster key of another table in the same cluster

7 Hash cluster key = constant

8 Entire cluster key = constant

[@more@]

9 Entire non-UNIQUE CONCATENATED index = constant

10 Non-UNIQUE index merge

11 Entire concatenated index = lower bound

12 Most leading column(s) of concatenated index = constant

13 Indexed column between low value and high value or indexed column LIKE "ABC%"

(bounded range)

14 Non-UNIQUE indexed column between low value and high value or indexed column like

`ABC%' (bounded range)

15 UNIQUE indexed column or constant (unbounded range)

16 Non-UNIQUE indexed column or constant (unbounded range)

17 Equality on non-indexed = column or constant (sort/merge join)

18 MAX or MIN of single indexed columns

19 ORDER BY entire index

20 Full table scans

RBO的头脑很简单,他只是按照这个Rank来进行执行路径的选择。举个最简单的例子,如果一个表是有索引,那么RBO是不会选择进行全表扫描的,因为全表扫描的Rank20,是最低的,RBO认为全表扫描的效率最低。(事实上,大家知道这是不一定的)。但是除去这20条规则,RBO还有一些其他要遵循的原则,下面就逐个介绍一下。

1. What the RBO rules don't tell you #1

只有单列的索引可以被合并

SELECT col1, ...

FROM emp

WHERE emp_name = 'GURRY'

AND emp_no = 127

AND dept_no = 12

Index1 (dept_no)

Index2 (emp_no, emp_name)

这个select语句中的where条件里面包括两个索引中的全部索引列。大家可能会觉得oracle会将Index1Index2合并来进行查询,但实际上oracle只会选择Index2。因为Index2并不是单列索引,RBO的索引合并的前提就是两个索引必须是单列,否则是不会进行索引合并的。RBO不会合并一个多列索引和一个单列索引的。

但是如果Index1是主键或着唯一索引,那么RBO会选择这个索引。比较rang4rank9

注:在oracle8i以后增加一个hint index_join。通过这个hint可以合并多列索引和单列索引。例如:

select /*+index_join(test_05(ind_test_05_owner ind_test_05_id))*/ *

from test_05

where owner='SYS'

AND object_name = 'I_CON1'

and object_id ='48'

/

2. What the RBO rules don't tell you #2

如果一个索引的全部列都在where条件中提供,而另一个索引只有部分列在where条件中,那么RBO会选择前者。

SELECT col1, ...

FROM emp

WHERE emp_name = 'GURRY'

AND emp_no = 127

AND dept_no = 12

Index1 (emp_name)

Index2 (emp_no, dept_no, cost_center)

此时RBO会选择Index1,因为Index1的全部索引列都在where条件中,而Index2仅有一部分。

3. What the RBO rules don't tell you #3

如果两个多列索引的索引列都出现在where中,并且他们出现在where条件中的列的比重相同,那么RBO会选择最近一个被更新的索引(创建或修改)。

SELECT col1, ...

FROM emp

WHERE emp_name = 'GURRY'

AND emp_no = 127

AND dept_no = 12

AND emp_category = 'CLERK'

Index1 (emp_name, emp_category) Created 4pm Feb 11 2002

Index2 (emp_no, dept_no) Created 5pm Feb 11 2002

此时只有Index2会被引用,因为Index2的创建时间是5pm,要比Index1的创建时间晚。所以就存在一个问题,当你对Index1进行rebuild的时候,这个sql就会选择Index1,会改变原来的执行计划。这可能会引起很大的性能问题。

正因为如此,在这种情况下,indexmodify顺序就变得很重要,大家一定要注意。

4. What the RBO rules don't tell you #4

如果一个多列索引列的操作符为 = ,那么他的优先级会大于其他索引列操作符为like between的多列索引。

SELECT col1, ...

FROM emp

WHERE emp_name LIKE 'GUR%'

AND emp_no = 127

AND dept_no = 12

AND emp_category = 'CLERK'

AND emp_class = 'C1'

Index1 (emp_category, emp_class, emp_name)

Index2 (emp_no, dept_no)

这个sql只有Index2会别引用,因为优先级 = 要大于 like

5. What the RBO rules don't tell you #5

在其他情况都相同的情况下,多列索引的索引列在where中引用的比例高的索引会优先被使用。当然如果是主键会唯一索引的话,会优先被选择。

SELECT col1, ...

FROM emp

WHERE emp_name = 'GURRY'

AND emp_no = 127

AND emp_class = 'C1'

Index1 (emp_name, emp_class, emp_category)

Index2 (emp_no, dept_no)

在这个sql里面Index1会被选择,因为Index166%的列的被引用,而Index2仅仅有50%被引用。

6. What the RBO rules don't tell you #6

当你进行两个表的连接操作时,RBO会选择一张表作为驱动表。驱动表的选择对性能的影响是很大的,特别是优化器决定采用nested loops嵌套循环连接的时候。Oracle会从驱动表检索出一条记录,然后到另外一张表中匹配,所以驱动表中的记录应该尽可能的少,这样性能会比较高。

RBO优化器采用下面的规则来选择优化器:

where条件中存在主键或者唯一索引的表会优先被选择为驱动表

where条件中索引列的操作符为 = 的表会优先与索引列操作符为 like 的表被选择驱动表。

where条件中索引列所占比重比较高的表优先被选择为驱动表

where条件中一个多列索引的表会优先与多个单列索引的表被选择为驱动表

。如果两个表的各方便都相同,那么在from列表中最后的表被选择为驱动表

SELECT ....

FROM DEPT d, EMP e

WHERE e.emp_name = 'GURRY'

AND d.dept_name = 'FINANCE'

AND d.dept_no = e.dept_no

7. What the RBO rules don't tell you #7

如果where条件中的索引列为一个索引的前缀列,那么这个索引会被优先选择。

SELECT col1, ...

FROM emp

WHERE emp_name = 'GURRY'

Index1 (emp_name, emp_class, emp_category)

Index2 (emp_class, emp_name, emp_category)

Index1会被优先选择。

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/8394333/viewspace-987148/,如需转载,请注明出处,否则将追究法律责任。

上一篇: Oracle的验证方式
请登录后发表评论 登录
全部评论
  • 博文量
    56
  • 访问量
    759889