Oracle提供了大量索引选项知道在给定条件下使用哪个选项对于一个应用程序的性能来说非常重要一个错误的选择可能会引发死锁并导致数据库性能急剧下降或进程终止而如果做出正确的选择则可以合理使用资源使那些已经运行了几个小时甚至几天的进程在几分钟得以完成这样会使您立刻成为一位英雄这篇文章就将简单的讨论每个索引选项主要有以下内容
[] 基本的索引概念
查询DBA_INDEXES视图可得到表中所有索引的列表注意只能通过USER_INDEXES的方法来检索模式(schema)的索引访问USER_IND_COLUMNS视图可得到一个给定表中被索引的特定列
[] 组合索引
当某个索引包含有多个已索引的列时称这个索引为组合(concatented)索引在 Oraclei引入跳跃式扫描的索引访问方法之前查询只能在有限条件下使用该索引比如表emp有一个组合索引键该索引包含了empnoename和deptno在Oraclei之前除非在where之句中对第一列(empno)指定一个值否则就不能使用这个索引键进行一次范围扫描
特别注意在Oraclei之前只有在使用到索引的前导索引时才可以使用组合索引!
[] ORACLE ROWID
通过每个行的ROWID索引Oracle提供了访问单行数据的能力ROWID其实就是直接指向单独行的线路图如果想检查重复值或是其他对ROWID本身的引用可以在任何表中使用和指定rowid列
[] 限制索引
限制索引是一些没有经验的开发人员经常犯的错误之一在SQL中有很多陷阱会使一些索引无法使用下面讨论一些常见的问题
使用不等于操作符(<>!=)
下面的查询即使在cust_rating列有一个索引查询语句仍然执行一次全表扫描
select cust_Idcust_name
from customers
wherecust_rating <> aa;
把上面的语句改成如下的查询语句这样在采用基于规则的优化器而不是基于代价的优化器(更智能)时将会使用索引
select cust_Idcust_name
from customers
wherecust_rating < aa or cust_rating > aa;
特别注意通过把不等于操作符改成OR条件就可以使用索引以避免全表扫描
使用IS NULL 或IS NOT NULL
使用IS NULL 或IS NOT NULL同样会限制索引的使用因为NULL值并没有被定义在SQL语句中使用NULL会有很多的麻烦因此建议开 发人员在建表时把需要索引的列设成NOT NULL如果被索引的列在某些行中存在NULL值就不会使用这个索引(除非索引是一个位图索 引关于位图索引在稍后在详细讨论)
使用函数
如果不使用基于函数的索引那么在SQL语句的WHERE子句中对存在索引的列使用函数时会使优化器忽略掉这些索引
下面的查询不会使用索引(只要它不是基于函数的索引)
select empnoenamedeptno
from emp
wheretrunc(hiredate)=MAY;
把上面的语句改成下面的语句这样就可以通过索引进行查找
select empnoenamedeptno
from emp
wherehiredate<(to_date(MAY)+);
比较不匹配的数据类型
比较不匹配的数据类型也是比较难于发现的性能问题之一
注意下面查询的例子account_number是一个VARCHAR类型在account_number字段上有索引下面的语句将执行全表扫描
select bank_nameaddresscitystatezip
from banks
whereaccount_number = ;
Oracle可以自动把where子句变成to_number(account_number)=这样就限制了索引的使用改成下面的查询就可以使用索引
select bank_nameaddresscitystatezip
from banks
whereaccount_number =;
特别注意不匹配的数据类型之间比较会让Oracle自动限制索引的使用即便对这个查询执行Explain Plan也不能让您明白为什么做了一 次全表扫描
[] 选择性
使用USER_INDEXES视图该视图中显示了一个distinct_keys列比较一下唯一键的数量和表中的行数就可以判断索引的选择性选择性越高索引返回的数据就越少
[] 群集因子(Clustering Factor)
Clustering Factor位于USER_INDEXES视图中该列反映了数据相对于已索引的列是否显得有序如果Clustering Factor列的值接近于索引中的树叶块(leaf block)的数目表中的数据就越有序如果它的值接近于表中的行数则表中的数据就不是很有序
[] 二元高度(Binary height)
索引的二元高度对把ROWID返回给用户进程时所要求的I/O量起到关键作用在对一个索引进行分析后可以通过查询DBA_INDEXES的Blevel列查看它的二元高度二元高度主要随着表的大小以及被索引的列中值的范围的狭窄程度而变化索引上如果有大量被删除的行它的二元高度也会增加更新索引列也类似于删除操作因为它增加了已删除键的数目重建索引可能会降低二元高度
[] 快速全局扫描
在Oracle后就可以使用快速全局扫描(Fast Full Scan)这个选项这个选项允许Oracle执行一个全局索引扫描操作快速全局扫描读取B树索引上所有树叶块初始化文件中的DB_FILE_MULTIBLOCK_READ_COUNT参数可以控制同时被读取的块的数目
[] 跳跃式扫描
从Oraclei开始索引跳跃式扫描特性可以允许优化器使用组合索引即便索引的前导列没有出现在WHERE子句中索引跳跃式扫描比全索引扫描要快的多下面的程序清单显示出性能的差别
create index skip on emp(jobempno);
index created
select count(*)
from emp
where empno=;
Elapsed:::
Execution Plan
SELECT STATEMENT Optimizer=CHOOSE(Cost= Card= Bytes=)
SORT(AGGREGATE)
INDEX(FAST FULL SCAN) OF SKIP(NONUNIQUE)
Statistics
consistent gets
physical reads
select /*+ index(emp skip)*/ count(*)
from emp
where empno=;
Elapsed:::
Execution Plan
SELECT STATEMENT Optimizer=CHOOSE(Cost= Card= Bytes=)
SORT(AGGREGATE)
INDEX(SKIP SCAN) OF SKIP(NONUNIQUE)
Statistics
consistent gets
physical reads
[] 索引的类型
B树索引
位图索引
HASH索引
索引编排表
反转键索引
基于函数的索引
分区索引
本地和全局索引