61阅读

oracle索引-Oracle之索引(Index)实例讲解 - 基础

发布时间:2017-09-03 所属栏目:oracle分析函数详解

一 : Oracle之索引(Index)实例讲解 - 基础

Oracle索引(Index)是关系数据库中用于存放表中每一条记录位置的一种对象,主要目的是加快数据的读取速度和数据的完整性检查。索引的建立是一项技术性要求非常高的工作。

(www.61k.com。

一般在数据库设计阶段就要考虑到如何设计和创建索引。

1. 创建索引

创建索引的语法:

 CREATE [UNIQUE] INDEX [schema.] index
ON [schema.] table (column [ASC | DESC], column [ASC | DESC]...)
[CLUSTER schema.cluster]
[INITRANS n]
[MAXTRANS n]
[PCTFREE n]
[STORAGE storage]
[TABLESPACE tablespace]
[NO SORT]

关键字说明:

UNIQUE: 该参数用来指明所创建的索引为唯一索引。

CLUSTER: 该参数为可选参数,用来指定一个聚簇(Hash cluster 不能创建索引)。

INITRANS, MAXTRANS: 为可选参数,指定初始和最大的事务入口数。

TABLESPACE: 索引的存储表空间。

STORAGE: 存储参数。

PCTFREE: 索引数据块空闲的百分比。

NO SORT: 不排序(存储时就按照升序进行排序,所以这里指出不再排序)。

示例:创建一张产品表(tb_product),为该表的product_id列创建索引,以便在使用到该列时提高查询效率。

create table tb_product
(
 product_id       number
, product_name      varchar2(100)
, product_type      varchar2(20)
, product_unit      varchar2(50)
, product_unit_price   number(10,4)
);

下面代码用来在product_id列上创建唯一索引:

create unique index product_id_u1 on tb_product(product_id);

2. 修改索引

索引的修改主要由数据库管理员完成,修改索引主要涉及到修改索引的存储参数、重建索引、对无用的索引空间进行合并等。

修改索引的语法:

ALTER [UNIQUE] INDEX [user.] index
INITRANS n
MAXTRANS n
REBUILD
[STORAGE <storage>]

说明:

INITRANS n: 表示一个块内同时访问的初始事务的入口数,n为十进制整数。

MAXTRANS n: 表示一个块内同时访问的最大事务入口数,n为十进制整数。

REBUILD: 表示根据原来的索引结构重新建立索引,也就是重新对表进行全表扫描以后创建索引数据。

STORAGE : 表示存储数据。

示例:

使用ALTER INDEX语句修改索引参数:

ALTER INDEX product_id_u1 REBUILD STORAGE ( INITIAL 1M NEXT 512K );

使用ALTER INDEX语句修改索引为逆向索引:

ALTER INDEX product_id_u1 REBUILD REVERSE;

使用ALTER INDEX语句合并索引空间:

ALTER INDEX product_id_u1 COALESCE;

3. 删除索引

可以使用DROP语句删除索引。

DROP INDEX schema.index;

在CentOS6.4下安装Oracle 11gR2(x64)

Oracle 11gR2 在VMWare虚拟机中安装步骤

Debian 下 安装 Oracle 11g XE R2

Oracle性能优化 之 共享池

更多Oracle相关信息见Oracle专题页面http://www.linuxidc.com/topicnews.aspx?tid=12

作者: 戴维德 联系方式:david.louis.tian@outlook.com

本文永久更新链接地址

二 : Oracle 索引 详解

一.索引介绍

1.1 索引的创建语法:

CREATE UNIUQE | BITMAP INDEX <schema>.<index_name>

ON <schema>.<table_name>

(<column_name> | <expression> ASC | DESC,

<column_name> | <expression> ASC | DESC,...)

TABLESPACE <tablespace_name>

STORAGE <storage_settings>

LOGGING | NOLOGGING

COMPUTE STATISTICS

NOCOMPRESS | COMPRESS<nn>

NOSORT | REVERSE

PARTITION | GLOBAL PARTITION<partition_setting>

相关说明

1)UNIQUE | BITMAP:指定UNIQUE为唯一值索引,BITMAP为位图索引,省略为B-Tree索引。

2)<column_name> | <expression> ASC | DESC:可以对多列进行联合索引,当为expression时即“基于函数的索引”

3)TABLESPACE:指定存放索引的表空间(索引和原表不在一个表空间时效率更高)

4)STORAGE:可进一步设置表空间的存储参数

5)LOGGING | NOLOGGING:是否对索引产生重做日志(对大表尽量使用NOLOGGING来减少占用空间并提高效率)

6)COMPUTE STATISTICS:创建新索引时收集统计信息

7)NOCOMPRESS | COMPRESS<nn>:是否使用“键压缩”(使用键压缩可以删除一个键列中出现的重复值)

8)NOSORT | REVERSE:NOSORT表示与表中相同的顺序创建索引,REVERSE表示相反顺序存储索引值

9)PARTITION | NOPARTITION:可以在分区表和未分区表上对创建的索引进行分区

1.2 索引特点:

第一,通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。

第二,可以大大加快数据的检索速度,这也是创建索引的最主要的原因。

第三,可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。

第四,在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间。

第五,通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。

1.3 索引不足:

第一,创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加。

第二,索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果要建立聚簇索引,那么需要的空间就会更大。

第三,当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,这样就降低了数据的维护速度。

1.4 应该建索引列的特点:

1)在经常需要搜索的列上,可以加快搜索的速度;

2)在作为主键的列上,强制该列的唯一性和组织表中数据的排列结构;

3)在经常用在连接的列上,这些列主要是一些外键,可以加快连接的速度;

4)在经常需要根据范围进行搜索的列上创建索引,因为索引已经排序,其指定的范围是连续的;

5)在经常需要排序的列上创建索引,因为索引已经排序,这样查询可以利用索引的排序,加快排序查询时间;

6)在经常使用在WHERE子句中的列上面创建索引,加快条件的判断速度。

1.5 不应该建索引列的特点:

第一,对于那些在查询中很少使用或者参考的列不应该创建索引。这是因为,既然这些列很少使用到,因此有索引或者无索引,并不能提高查询速度。相反,由于增加了索引,反而降低了系统的维护速度和增大了空间需求。

第二,对于那些只有很少数据值的列也不应该增加索引。这是因为,由于这些列的取值很少,例如人事表的性别列,在查询的结果中,结果集的数据行占了表中数据行的很大比例,即需要在表中搜索的数据行的比例很大。增加索引,并不能明显加快检索速度。

第三,对于那些定义为blob数据类型的列不应该增加索引。这是因为,这些列的数据量要么相当大,要么取值很少。

第四,当修改性能远远大于检索性能时,不应该创建索引。这是因为,修改性能和检索性能是互相矛盾的。当增加索引时,会提高检索性能,但是会降低修改性能。当减少索引时,会提高修改性能,降低检索性能。因此,当修改性能远远大于检索性能时,不应该创建索引。

1.6 限制索引

限制索引是一些没有经验的开发人员经常犯的错误之一。在SQL中有很多陷阱会使一些索引无法使用。下面讨论一些常见的问题:

1.6.1 使用不等于操作符(<>、!=)

下面的查询即使在cust_rating列有一个索引,查询语句仍然执行一次全表扫描。

select cust_Id,cust_name from customers where cust_rating <> &#39;aa&#39;;

把上面的语句改成如下的查询语句,这样,在采用基于规则的优化器而不是基于代价的优化器(更智能)时,将会使用索引。

select cust_Id,cust_name from customers where cust_rating < &#39;aa&#39; or cust_rating > &#39;aa&#39;;

特别注意:通过把不等于操作符改成OR条件,就可以使用索引,以避免全表扫描。

1.6.2 使用IS NULL 或IS NOT NULL

使用IS NULL 或IS NOT NULL同样会限制索引的使用。因为NULL值并没有被定义。在SQL语句中使用NULL会有很多的麻烦。因此建议开发人员在建表时,把需要索引的列设成NOT NULL。如果被索引的列在某些行中存在NULL值,就不会使用这个索引(除非索引是一个位图索引,关于位图索引在稍后在详细讨论)。

1.6.3 使用函数

如果不使用基于函数的索引,那么在SQL语句的WHERE子句中对存在索引的列使用函数时,会使优化器忽略掉这些索引。 下面的查询不会使用索引(只要它不是基于函数的索引)

select empno,ename,deptno from emp where trunc(hiredate)=&#39;01-MAY-81&#39;;

把上面的语句改成下面的语句,这样就可以通过索引进行查找。

select empno,ename,deptno from emp where hiredate<(to_date(&#39;01-MAY-81&#39;)+0.9999);

1.6.4 比较不匹配的数据类型

也是比较难于发现的性能问题之一。 注意下面查询的例子,account_number是一个VARCHAR2类型,在account_number字段上有索引。

下面的语句将执行全表扫描:

扩展:oracle11g 索引详解 / mysql索引详解 / 索引详解

select bank_name,address,city,state,zip from banks where account_number = 990354;

Oracle可以自动把where子句变成to_number(account_number)=990354,这样就限制了索引的使用,改成下面的查询就可以使用索引:

select bank_name,address,city,state,zip from banks where account_number =&#39;990354&#39;;

特别注意:不匹配的数据类型之间比较会让Oracle自动限制索引的使用,即便对这个查询执行Explain Plan也不能让您明白为什么做了一次“全表扫描”。

1.7 查询索引

查询DBA_INDEXES视图可得到表中所有索引的列表,注意只能通过USER_INDEXES的方法来检索模式(schema)的索引。访问USER_IND_COLUMNS视图可得到一个给定表中被索引的特定列。

1.8 组合索引

当某个索引包含有多个已索引的列时,称这个索引为组合(concatented)索引。在Oracle9i引入跳跃式扫描的索引访问方法之前,查询只能在有限条件下使用该索引。比如:表emp有一个组合索引键,该索引包含了empno、ename和deptno。在Oracle9i之前除非在where之句中对第一列(empno)指定一个值,否则就不能使用这个索引键进行一次范围扫描。

特别注意:在Oracle9i之前,只有在使用到索引的前导索引时才可以使用组合索引!

1.9 ORACLE ROWID

通过每个行的ROWID,索引Oracle提供了访问单行数据的能力。ROWID其实就是直接指向单独行的线路图。如果想检查重复值或是其他对ROWID本身的引用,可以在任何表中使用和指定rowid列。

1.10 选择性

使用USER_INDEXES视图,该视图中显示了一个distinct_keys列。比较一下唯一键的数量和表中的行数,就可以判断索引的选择性。选择性越高,索引返回的数据就越少。

1.11 群集因子(Clustering Factor)

Clustering Factor位于USER_INDEXES视图中。该列反映了数据相对于已建索引的列是否显得有序。如果Clustering Factor列的值接近于索引中的树叶块(leaf block)的数目,表中的数据就越有序。如果它的值接近于表中的行数,则表中的数据就不是很有序。

1.12 二元高度(Binary height)

索引的二元高度对把ROWID返回给用户进程时所要求的I/O量起到关键作用。在对一个索引进行分析后,可以通过查询DBA_INDEXES的B- level列查看它的二元高度。二元高度主要随着表的大小以及被索引的列中值的范围的狭窄程度而变化。索引上如果有大量被删除的行,它的二元高度也会增加。更新索引列也类似于删除操作,因为它增加了已删除键的数目。重建索引可能会降低二元高度。

1.13 快速全局扫描

从Oracle7.3后就可以使用快速全局扫描(Fast Full Scan)这个选项。这个选项允许Oracle执行一个全局索引扫描操作。快速全局扫描读取B-树索引上所有树叶块。初始化文件中的DB_FILE_MULTIBLOCK_READ_COUNT参数可以控制同时被读取的块的数目。

1.14 跳跃式扫描

从Oracle9i开始,索引跳跃式扫描特性可以允许优化器使用组合索引,即便索引的前导列没有出现在WHERE子句中。索引跳跃式扫描比全索引扫描要快的多。

下面的比较他们的区别:

SQL> set timing on

SQL> create index TT_index on TT(teamid,areacode);

索引已创建。

已用时间: 00: 02: 03.93

SQL> select count(areacode) from tt;

COUNT(AREACODE)

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

7230369

已用时间: 00: 00: 08.31

SQL> select /*+ index(tt TT_index )*/ count(areacode) from tt;

COUNT(AREACODE)

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

7230369

已用时间: 00: 00: 07.37

1.15 索引的类型

B-树索引 位图索引 HASH索引 索引编排表

反转键索引 基于函数的索引 分区索引 本地和全局索引

二. 索引分类

Oracle提供了大量索引选项。知道在给定条件下使用哪个选项对于一个应用程序的性能来说非常重要。一个错误的选择可能会引发死锁,并导致数据库性能急剧下降或进程终止。而如果做出正确的选择,则可以合理使用资源,使那些已经运行了几个小时甚至几天的进程在几分钟得以完成,这样会使您立刻成为一位英雄。下面就将简单的讨论每个索引选项。

下面讨论的索引类型:

B树索引(默认类型)

位图索引

HASH索引

索引组织表索引

反转键(reverse key)索引

基于函数的索引

分区索引(本地和全局索引)

位图连接索引

2.1 B树索引(默认类型)

B树索引在Oracle中是一个通用索引。在创建索引时它就是默认的索引类型。B树索引可以是一个列的(简单)索引,也可以是组合/复合(多个列)的索引。B树索引最多可以包括32列。

在下图的例子中,B树索引位于雇员表的last_name列上。这个索引的二元高度为3;接下来,Oracle会穿过两个树枝块(branch block),到达包含有ROWID的树叶块。在每个树枝块中,树枝行包含链中下一个块的ID号。

树叶块包含了索引值、ROWID,以及指向前一个和后一个树叶块的指针。Oracle可以从两个方向遍历这个二叉树。B树索引保存了在索引列上有值的每个数据行的ROWID值。Oracle不会对索引列上包含NULL值的行进行索引。如果索引是多个列的组合索引,而其中列上包含NULL值,这一行就会处于包含NULL值的索引列中,且将被处理为空(视为NULL)。

技巧:索引列的值都存储在索引中。因此,可以建立一个组合(复合)索引,这些索引可以直接满足查询,而不用访问表。这就不用从表中检索数据,从而减少了I/O量。

B-tree 特点:

适合与大量的增、删、改(OLTP)

不能用包含OR操作符的查询;

适合高基数的列(唯一值多)

典型的树状结构;

每个结点都是数据块;

大多都是物理上一层、两层或三层不定,逻辑上三层;

叶子块数据是排序的,从左向右递增;

在分支块和根块中放的是索引的范围;

2.2 位图索引

位图索引非常适合于决策支持系统(Decision Support System,DSS)和数据仓库,它们不应该用于通过事务处理应用程序访问的表。它们可以使用较少到中等基数(不同值的数量)的列访问非常大的表。尽管位图索引最多可达30个列,但通常它们都只用于少量的列。

扩展:oracle11g 索引详解 / mysql索引详解 / 索引详解

例如,您的表可能包含一个称为Sex的列,它有两个可能值:男和女。这个基数只为2,如果用户频繁地根据Sex列的值查询该表,这就是位图索引的基列。当一个表内包含了多个位图索引时,您可以体会到位图索引的真正威力。如果有多个可用的位图索引,Oracle就可以合并从每个位图索引得到的结果集,快速删除不必要的数据。

Bitmapt 特点:

适合与决策支持系统;

做UPDATE代价非常高;

非常适合OR操作符的查询;

基数比较少的时候才能建位图索引;

技巧:对于有较低基数的列需要使用位图索引。性别列就是这样一个例子,它有两个可能值:男或女(基数仅为2)。位图对于低基数(少量的不同值)列来说非常快,这是因为索引的尺寸相对于B树索引来说小了很多。因为这些索引是低基数的B树索引,所以非常小,因此您可以经常检索表中超过半数的行,并且仍使用位图索引。

当大多数条目不会向位图添加新的值时,位图索引在批处理(单用户)操作中加载表(插入操作)方面通常要比B树做得好。当多个会话同时向表中插入行时不应该使用位图索引,在大多数事务处理应用程序中都会发生这种情况。

示例

下面来看一个示例表PARTICIPANT,该表包含了来自个人的调查数据。列Age_Code、Income_Level、Education_Level和Marital_Status都包括了各自的位图索引。下图显示了每个直方图中的数据平衡情况,以及对访问每个位图索引的查询的执行路径。图中的执行路径显示了有多少个位图索引被合并,可以看出性能得到了显著的提高。

如上图图所示,优化器依次使用4个单独的位图索引,这些索引的列在WHERE子句中被引用。每个位图记录指针(例如0或1),用于指示表中的哪些行包含位图中的已知值。有了这些信息后,Oracle就执行BITMAP AND操作以查找将从所有4个位图中返回哪些行。该值然后被转换为ROWID值,并且查询继续完成剩余的处理工作。注意,所有4个列都有非常低的基数,使用索引可以非常快速地返回匹配的行。

技巧:在一个查询中合并多个位图索引后,可以使性能显著提高。位图索引使用固定长度的数据类型要比可变长度的数据类型好。较大尺寸的块也会提高对位图索引的存储和读取性能。

下面的查询可显示索引类型。

SQL> select index_name, index_type from user_indexes;

INDEX_NAME INDEX_TYPE

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

TT_INDEX NORMAL

IX_CUSTADDR_TP NORMAL

B树索引作为NORMAL列出;而位图索引的类型值为BITMAP。

技巧:如果要查询位图索引列表,可以在USER _INDEXES视图中查询index_type列。

建议不要在一些联机事务处理(OLTP)应用程序中使用位图索引。B树索引的索引值中包含ROWID,这样Oracle就可以在行级别上锁定索引。位图索引存储为压缩的索引值,其中包含了一定范围的ROWID,因此Oracle必须针对一个给定值锁定所有范围内的ROWID。这种锁定类型可能在某些DML语句中造成死锁。SELECT语句不会受到这种锁定问题的影响。

位图索引的使用限制:

基于规则的优化器不会考虑位图索引。

当执行ALTER TABLE语句并修改包含有位图索引的列时,会使位图索引失效。

位图索引不包含任何列数据,并且不能用于任何类型的完整性检查。

位图索引不能被声明为唯一索引。

位图索引的最大长度为30。

技巧:不要在繁重的OLTP环境中使用位图索引

2.3 HASH索引

使用HASH索引必须要使用HASH集群。建立一个集群或HASH集群的同时,也就定义了一个集群键。这个键告诉Oracle如何在集群上存储表。在存储数据时,所有与这个集群键相关的行都被存储在一个数据库块上。如果数据都存储在同一个数据库块上,并且将HASH索引作为WHERE子句中的确切匹配,Oracle就可以通过执行一个HASH函数和I/O来访问数据——而通过使用一个二元高度为4的B树索引来访问数据,则需要在检索数据时使用4个I/O。如下图所示,其中的查询是一个等价查询,用于匹配HASH列和确切的值。Oracle可以快速使用该值,基于HASH函数确定行的物理存储位置。

HASH索引可能是访问数据库中数据的最快方法,但它也有自身的缺点。集群键上不同值的数目必须在创建HASH集群之前就要知道。需要在创建HASH集群的时候指定这个值。低估了集群键的不同值的数字可能会造成集群的冲突(两个集群的键值拥有相同的HASH值)。这种冲突是非常消耗资源的。冲突会造成用来存储额外行的缓冲溢出,然后造成额外的I/O。如果不同HASH值的数目已经被低估,您就必须在重建这个集群之后改变这个值。

ALTER CLUSTER命令不能改变HASH键的数目。HASH集群还可能浪费空间。如果无法确定需要多少空间来维护某个集群键上的所有行,就可能造成空间的浪费。如果不能为集群的未来增长分配好附加的空间,HASH集群可能就不是最好的选择。如果应用程序经常在集群表上进行全表扫描,HASH集群可能也不是最好的选择。由于需要为未来的增长分配好集群的剩余空间量,全表扫描可能非常消耗资源。

在实现HASH集群之前一定要小心。您需要全面地观察应用程序,保证在实现这个选项之前已经了解关于表和数据的大量信息。通常,HASH对于一些包含有序值的静态数据非常有效。

技巧:HASH索引在有限制条件(需要指定一个确定的值而不是一个值范围)的情况下非常有用。

2.4 索引组织表

索引组织表会把表的存储结构改成B树结构,以表的主键进行排序。这种特殊的表和其他类型的表一样,可以在表上执行所有的DML和DDL语句。由于表的特殊结构,ROWID并没有被关联到表的行上。

对于一些涉及精确匹配和范围搜索的语句,索引组织表提供了一种基于键的快速数据访问机制。基于主键值的UPDATE和DELETE语句的性能也同样得以提高,这是因为行在物理上有序。由于键列的值在表和索引中都没有重复,存储所需要的空间也随之减少。

如果不会频繁地根据主键列查询数据,则需要在索引组织表中的其他列上创建二级索引。不会频繁根据主键查询表的应用程序不会了解到使用索引组织表的全部优点。对于总是通过对主键的精确匹配或范围扫描进行访问的表,就需要考虑使用索引组织表。

扩展:oracle11g 索引详解 / mysql索引详解 / 索引详解

技巧:可以在索引组织表上建立二级索引。

2.5 反转键索引

当载入一些有序数据时,索引肯定会碰到与I/O相关的一些瓶颈。在数据载入期间,某部分索引和磁盘肯定会比其他部分使用频繁得多。为了解决这个问题,可以把索引表空间存放在能够把文件物理分割在多个磁盘上的磁盘体系结构上。

为了解决这个问题,Oracle还提供了一种反转键索引的方法。如果数据以反转键索引存储,这些数据的值就会与原先存储的数值相反。这样,数据1234、1235和1236就被存储成4321、5321和6321。结果就是索引会为每次新插入的行更新不同的索引块。

技巧:如果您的磁盘容量有限,同时还要执行大量的有序载入,就可以使用反转键索引。

不可以将反转键索引与位图索引或索引组织表结合使用。因为不能对位图索引和索引组织表进行反转键处理。

2.6 基于函数的索引

可以在表中创建基于函数的索引。如果没有基于函数的索引,任何在列上执行了函数的查询都不能使用这个列的索引。例如,下面的查询就不能使用JOB列上的索引,除非它是基于函数的索引:

select * from emp where UPPER(job) = &#39;MGR&#39;;

下面的查询使用JOB列上的索引,但是它将不会返回JOB列具有Mgr或mgr值的行:

select * from emp where job = &#39;MGR&#39;;

可以创建这样的索引,允许索引访问支持基于函数的列或数据。可以对列表达式UPPER(job)创建索引,而不是直接在JOB列上建立索引,如:

create index EMP$UPPER_JOB on emp(UPPER(job));

尽管基于函数的索引非常有用,但在建立它们之前必须先考虑下面一些问题:

能限制在这个列上使用的函数吗?如果能,能限制所有在这个列上执行的所有函数吗

是否有足够应付额外索引的存储空间?

在每列上增加的索引数量会对针对该表执行的DML语句的性能带来何种影响?

基于函数的索引非常有用,但在实现时必须小心。在表上创建的索引越多,INSERT、UPDATE和DELETE语句的执行就会花费越多的时间。

注意:对于优化器所使用的基于函数的索引来说,必须把初始参数QUERY _REWRITE _ ENABLED设定为TRUE。

示例:

select count(*) from sample where ratio(balance,limit) >.5;

Elapsed time: 20.1 minutes

create index ratio_idx1 on sample (ratio(balance, limit));

select count(*) from sample where ratio(balance,limit) >.5;

Elapsed time: 7 seconds!!!

2.7 分区索引

分区索引就是简单地把一个索引分成多个片断。通过把一个索引分成多个片断,可以访问更小的片断(也更快),并且可以把这些片断分别存放在不同的磁盘驱动器上(避免I/O问题)。B树和位图索引都可以被分区,而HASH索引不可以被分区。可以有好几种分区方法:表被分区而索引未被分区;表未被分区而索引被分区;表和索引都被分区。不管采用哪种方法,都必须使用基于成本的优化器。分区能够提供更多可以提高性能和可维护性的可能性

有两种类型的分区索引:本地分区索引和全局分区索引。每个类型都有两个子类型,有前缀索引和无前缀索引。表各列上的索引可以有各种类型索引的组合。如果使用了位图索引,就必须是本地索引。把索引分区最主要的原因是可以减少所需读取的索引的大小,另外把分区放在不同的表空间中可以提高分区的可用性和可靠性。

在使用分区后的表和索引时,Oracle还支持并行查询和并行DML。这样就可以同时执行多个进程,从而加快处理这条语句。

2.7.1.本地分区索引(通常使用的索引)

可以使用与表相同的分区键和范围界限来对本地索引分区。每个本地索引的分区只包含了它所关联的表分区的键和ROWID。本地索引可以是B树或位图索引。如果是B树索引,它可以是唯一或不唯一的索引。

这种类型的索引支持分区独立性,这就意味着对于单独的分区,可以进行增加、截取、删除、分割、脱机等处理,而不用同时删除或重建索引。Oracle自动维护这些本地索引。本地索引分区还可以被单独重建,而其他分区不会受到影响。

2.7.1.1 有前缀的索引

有前缀的索引包含了来自分区键的键,并把它们作为索引的前导。例如,让我们再次回顾participant表。在创建该表后,使用survey_id和survey_date这两个列进行范围分区,然后在survey_id列上建立一个有前缀的本地索引,如下图所示。这个索引的所有分区都被等价划分,就是说索引的分区都使用表的相同范围界限来创建。

oracle索引 Oracle 索引 详解

技巧:本地的有前缀索引可以让Oracle快速剔除一些不必要的分区。也就是说没有包含WHERE条件子句中任何值的分区将不会被访问,这样也提高了语句的性能。

2.7.1.2 无前缀的索引

无前缀的索引并没有把分区键的前导列作为索引的前导列。若使用有同样分区键(survey_id和survey_date)的相同分区表,建立在survey_date列上的索引就是一个本地的无前缀索引,如下图所示。可以在表的任一列上创建本地无前缀索引,但索引的每个分区只包含表的相应分区的键值。

oracle索引 Oracle 索引 详解

如果要把无前缀的索引设为唯一索引,这个索引就必须包含分区键的子集。在这个例子中,我们必须把包含survey和(或)survey_id的列进行组合(只要survey_id不是索引的第一列,它就是一个有前缀的索引)。

技巧:对于一个唯一的无前缀索引,它必须包含分区键的子集。

2.7.2. 全局分区索引

全局分区索引在一个索引分区中包含来自多个表分区的键。一个全局分区索引的分区键是分区表中不同的或指定一个范围的值。在创建全局分区索引时,必须定义分区键的范围和值。全局索引只能是B树索引。Oracle在默认情况下不会维护全局分区索引。如果一个分区被截取、增加、分割、删除等,就必须重建全局分区索引,除非在修改表时指定ALTER TABLE命令的UPDATE GLOBAL INDEXES子句。

2.7.2.1 有前缀的索引

通常,全局有前缀索引在底层表中没有经过对等分区。没有什么因素能限制索引的对等分区,但Oracle在生成查询计划或执行分区维护操作时,并不会充分利用对等分区。如果索引被对等分区,就必须把它创建为一个本地索引,这样Oracle可以维护这个索引,并使用它来删除不必要的分区,如下图所示。在该图的3个索引分区中,每个分区都包含指向多个表分区中行的索引条目。

扩展:oracle11g 索引详解 / mysql索引详解 / 索引详解

oracle索引 Oracle 索引 详解

分区的、全局有前缀索引

技巧:如果一个全局索引将被对等分区,就必须把它创建为一个本地索引,这样Oracle可以维护这个索引,并使用它来删除不必要的分区。

2.7.2.2 无前缀的索引

Oracle不支持无前缀的全局索引。

2.8 位图连接索引

位图连接索引是基于两个表的连接的位图索引,在数据仓库环境中使用这种索引改进连接维度表和事实表的查询的性能。创建位图连接索引时,标准方法是连接索引中常用的维度表和事实表。当用户在一次查询中结合查询事实表和维度表时,就不需要执行连接,因为在位图连接索引中已经有可用的连接结果。通过压缩位图连接索引中的ROWID进一步改进性能,并且减少访问数据所需的I/O数量。

创建位图连接索引时,指定涉及的两个表。相应的语法应该遵循如下模式:

create bitmap index FACT_DIM_COL_IDX on FACT(DIM.Descr_Col) from FACT, DIM

where FACT.JoinCol = DIM.JoinCol;

位图连接的语法比较特别,其中包含FROM子句和WHERE子句,并且引用两个单独的表。索引列通常是维度表中的描述列——就是说,如果维度是CUSTOMER,并且它的主键是CUSTOMER_ID,则通常索引Customer_Name这样的列。如果事实表名为SALES,可以使用如下的命令创建索引:

create bitmap index SALES_CUST_NAME_IDX

on SALES(CUSTOMER.Customer_Name) from SALES, CUSTOMER

where SALES.Customer_ID=CUSTOMER.Customer_ID;

如果用户接下来使用指定Customer_Name列值的WHERE子句查询SALES和CUSTOMER表,优化器就可以使用位图连接索引快速返回匹配连接条件和Customer_Name条件的行。

位图连接索引的使用一般会受到限制:

1)只可以索引维度表中的列。

2)用于连接的列必须是维度表中的主键或唯一约束;如果是复合主键,则必须使用连接中的每一列。

3)不可以对索引组织表创建位图连接索引,并且适用于常规位图索引的限制也适用于位图连接索引。

注: 本文整理自《Oracle Database 10g 性能调整与优化》

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

Blog:blog.csdn.net/tianlesoftware

扩展:oracle11g 索引详解 / mysql索引详解 / 索引详解

三 : ORACLE索引概述

ORACLE索引概述

索引是数据库中一种可选的数据结构,她通常与表或簇相关。用户可以在表的一列或数列上建立索引,以提高在此表上执行 SQL 语句的性能。就像本文档的索引可以帮助读者快速定位所需信息一样,Oracle的索引提供了更为迅速地访问表数据的方式。正确地使用索引能够显著的减少磁盘 I/O。

用户可以为一个表创建多个索引,只要不同索引使用的列或列的组合(combination of columns)不同即可。例如,下列语句中指定的列组合是有效的:

CREATE INDEX employees_idx1 ON employees (last_name, job_id);

CREATE INDEX employees_idx2 ON employees (job_id, last_name);

Oracle 提供了各种类型的索引,她们能够互为补充地提升查询性能:

平衡树索引(B-tree index)

平衡树簇索引(B-tree cluster index)

哈希簇索引(hash cluster index)

反向键索引(reverse key indexes)

位图索引(bitmap index)

位图连接索引(bitmap join index)

Oracle 还支持函数索引(function-based index),以及针对特定应用程序或程序模块(cartridge)的域索引(domain index)。

无论索引是否存在都无需对已有的 SQL 语句进行修改。索引只是提供了一种快速访问数据的路径,因此她只会影响查询的执行速度。当给出一个已经被索引的数据值后,就可以通过索引直接地定位到包含此值的所有数据行。

索引在逻辑上和物理上都与其基表(base table)是相互独立的。用户可以随时创建(create)或移除(drop)一个索引,而不会影响其基表或基表上的其他索引。当用户移除一个索引时,所有的应用程序仍然能够继续工作,但是数据访问速度有可能会降低。作为一种独立的数据结构,索引需要占用存储空间。

当索引被创建后,对其的维护与使用都是 Oracle 自动完成的。当索引所依赖的数据发生插入,更新,删除等操作时,Oracle 会自动地将这些数据变化反映到相关的索引中,无需用户的额外操作。

即便索引的基表中插入新的数据,对被索引数据的查询性能基本上能够保持稳定不变。但是,如果在一个表上建立了过多的索引,将降低其插入,更新,及删除的性能。因为 Oracle 必须同时修改与此表相关的索引信息。

优化器可以使用已有的索引来建立(build)新的索引。这将加快新索引的建立速度。

5.8.1 唯一索引和非唯一索引

索引(index)可以是唯一(unique)的或非唯一(nonunique)的。在一个表上建立唯一索引(unique index)能够保证此表的索引列(一列或多列)不存在重复值。而非唯一索引(nonunique index)并不对索引列值进行这样的限制。

Oracle 建议使用 CREATE UNIQUE INDEX 语句显式地创建唯一索引(unique index)。通过主键(primary key)或唯一约束(unique constraint)来创建唯一索引不能保证创建新的索引,而且用这些方式创建的索引不能保证为唯一索引。

5.8.2 复合索引

复合索引(composite index)(也被称为连结索引(concatenated index))是指创建在一个表的多列上的索引。复合索引内的列可以任意排列,她们在数据表中也无需相邻。

如果一个 SELECT 语句的 WHERE 子句中引用了复合索引(composite index)的全部列(all of the column)或自首列开始且连续的部分列(leading portion of the column),将有助于提高此查询的性能。因此,索引定义中列的顺序是很重要的。大体上说,经常访问的列(most commonly accessed)或选择性较大的列(most selective)应该放在前面。

一个常规的(regular)复合索引(composite index)不能超过 32 列,而位图索引(bitmap index)不能超过 30 列。索引中一个键值(key value)的总长度大致上不应超过一个数据块(data block)总可用空间的一半。

5.8.3 索引和键

索引(index)与键(key)是连个不同的概念,但是这两个术语经常被混用。索引是在数据库中实际存储的数据结构,用户可以使用 SQL 语句对其进行创建(create),修改(alter),或移除(drop)。索引提供了一种快速访问表数据的途径。而键只是一个逻辑概念。键的概念主要在 Oracle 的完整性约束(integrity constraint)功能中使用,完整性约束用于保证数据库中的业务规则(business rule)。

因为 Oracle 也会使用索引(index)来实现某些完整性约束(integrity constraint),因此索引与键(key)这两个术语经常被混用。注意不要将二者混淆。

5.8.4 索引和空值

对于一个数据表的两行或多行,如果其索引列(key column)中全部非空(non-NULL)的值完全相同(identical),那么在索引中这些行将被认为是相同的;反之,在索引中这些行将被认为是不同的。因此使用 UNIQUE 索引可以避免将包含 NULL 的行视为相同的。以上讨论并不包括索引列的列值(column value)全部为 NULL 的情况。

Oracle 不会将索引列(key column)全部为 NULL 的数据行加入到索引中。不过位图索引(bitmap index)是个例外,簇键(cluster key)的列值(column value)全部为 NULL 时也是例外。

5.8.5 函数索引

如果一个函数(function)或表达式(expression)使用了一个表的一列或多列,则用户可以依据这些函数或表达式为表建立索引,这样的索引被称为函数索引(Function-Based Index)。函数索引能够计算出函数或表达式的值,并将其保存在索引中。用户创建的函数索引既可以是平衡树类型(B-tree index)的,也可以是位图类型(bitmap index)的。

用于创建索引的函数可以是一个数学表达式(arithmetic expression),也可以是使用了 PL/SQL 函数(PL/SQL function),包函数(package function),C 外部调用(C callout),或 SQL 函数(SQL function)的表达式。用于创建索引的函数不能包含任何聚合函数(ggregate function),如果为用户自定义函数,则在声明中必须使用 DETERMINISTIC关键字。如果在一个使用对象类型(object type)的列上建立函数索引,则可以使用此对象的方法(method)作为函数,例如此对象的 map 方法。用户不能在数据类型为 LOB,REF,或嵌套表(nested table)的列上建立函数索引,也不能在包含 LOB,REF,或嵌套表等数据类型的对象类型列上建立函数索引。

扩展:oracle 索引 / oracle 创建索引 / oracle 删除索引

5.8.5.1 使用函数索引

如果一个 SQL 语句的 WHERE 子句中使用了函数,那么建立相应的函数索引(function-based index)是提高数据访问性能的有效机制。表达式(expression)的结果经过计算后将被存储在索引中。但是当执行 INSERT 和 UPDATE 语句时,Oracle 需要进行函数运算以便维护索引。

例如,如果用户创建了以下函数索引:

CREATE INDEX idx ON table_1 (a + b * (c &ndash; 1), a, b);

当 Oracle 处理如下查询时就可以使用之前建立的索引:

SELECT a FROM table_1 WHERE a + b * (c &ndash; 1) < 100;

使用 UPPER(column_name) 或 LOWER(column_name) 函数建立函数索引(function-based index)有助于与大小写无关(case-insensitive)的查询。例如创建以下函数索引:

CREATE INDEX uppercase_idx ON employees (UPPER(first_name));

有助于提高以下查询的性能:

SELECT * FROM employees WHERE UPPER(first_name) = &lsquo;RICHARD&rsquo;;

5.8.5.2 函数索引的优化

用户必须为优化器(optimizer)收集关于函数索引(unction-based index)的统计信息(statistic)。否则处理 SQL 语句时将不会使用此索引。

当一个查询的 WHERE 子句中含有表达式(expression)时,优化器可以对函数索引(function-based index)进行索引区间扫描(index range scan)。例如以下查询:

SELECT * FROM t WHERE a + b < 10;

如果使用表达式(expression) a+b 建立的索引,优化器(optimizer)就能够进行索引区间扫描(index range scan)。如果谓词(predicate,即 WHERE 子句)产生的选择性(selectivity)较低,则对区间扫描极为有利。此外,如果表达式的结果物化在函数索引内(function-based index),优化器将能更准确地估计使用此表达式的谓词的选择性。

优化器(optimizer)能够将 SQL 语句及函数索引(function-based index)中的表达式解析为表达式树(expression tree)并进行比较,从而实现表达式匹配。这个比较过程是大小写无关的(case-insensitive),并将忽略所有空格(blank space)。

5.8.5.3 函数索引的依赖性

函数索引(function-based index)依赖于索引定义表达式中使用的函数。如果此函数为 PL/SQL 函数(PL/SQL function)或包函数(package function),当函数声明(function specification)发生变化时,索引将失效(disabled)。

用户需要被授予(grant)CREATE INDEX 或 CREATE ANY INDEX 权限才能创建函数索引(function-based index)。

要想使用函数索引(function-based index):

建立索引后,表必须经过分析(analyze)。

必须保证查询的条件表达式不是 NULL 值, 因为 NULL 值不会被存储到索引中。

以下各节将讲述使用函数索引的其他需求。

5.8.5.3.1 DETERMINISTIC 函数

函数索引(function-based index)使用的用户自定义函数(user-written function)必须声明为 DETERMINISTIC,此关键字表明对于一定的输入参数,此函数总会得到相同的输出结果。

5.8.5.3.2 定义函数的权限

函数索引(function-based index)的所有者(owner)必须具备此索引定义中使用的函数的EXECUTE 权限。当 EXECUTE 权限被收回(revoke)后,Oracle 则将索引标识为 DISABLED。索引的所有者无须具备此函数的 EXECUTE WITH GRANT OPTION 权限,即可将索引所在表的SELECT 权限授予(grant)其他用户。

5.8.5.3.3 解决函数索引的依赖性问题

函数索引(function-based index)依赖于她使用的所有函数。如果函数或函数所在包的声明(specification)被修改过(或索引所有者对函数的 EXECUTE 权限被收回),将会出现以下情况:

索引被标记为 DISABLED。

如果优化器(optimizer)选择了在标记为 DISABLED 的索引上执行查询,那么此查询将失败

使用标记为 DISABLED 的索引而执行的 DML 操作将失败,除非此索引同时被标记为UNUSABLE 且初始化参数(initialization parameter) SKIP_UNUSABLE_INDEXES 被设为TRUE。

函数被修改之后,用户可以使用 ALTER INDEX … ENABLE 语句将索引重新置为 ENABLE 状态。

5.8.6 索引是如何存储的

当用户创建索引时,Oracle 会自动地在表空间(tablespace)中创建索引段(index segment)来存储索引的数据。用户可以通过以下方式控制索引段的空间分配和使用:

设置索引段的存储参数(storage parameter)来控制如何为此索引段分配数据扩展(extent)

为索引段设置 PCTFREE 参数,来控制组成数据扩展的各个数据块(data block)的可用空间情况。

索引段(index segment)使用的表空间(tablespace)既可以是索引所有者(owner)的默认表空间,也可以是在 CREATE INDEX 语句中指定的表空间。索引无需和其相关的表位于同一表空间中。相反,如果将索引与其相关表存储在不同磁盘上能够提升使用此索引的查询性能,因为此时 Oracle 能够并行地(parallel)访问索引及表数据。

5.8.6.1 索引块的格式

一个数据块(data block)内可用于存储索引数据的空间等于数据块容量减去数据块管理开销(overhead),索引条目管理开销(entry overhead),rowid,及记录每个索引值长度的 1 字节(byte)。

当用户创建索引时,Oracle 取得所有被索引列的数据并进行排序,之后将排序后索引值和与此值相对应的 rowid 按照从下到上的顺序加载到索引中。例如,以下语句:

CREATE INDEX employees_last_name ON employees(last_name);

Oracle 先将 employees 表按 last_name 列排序,再将排序后的 列及相应的 rowid 按从下到上的顺序加载到索引中。使用此索引时,Oracle 可以快速地搜索已排序的 last_name 值,并使用相应的 rowid 去定位包含用户所查找的 last_name 值的数据行。

5.8.6.2 索引的内部结构

Oracle 使用平衡树(B-tree)存储索引以便提升数据访问速度。当不使用索引时,用户必须对数据进行顺序扫描(sequential scan)来查找指定的值。如果有 n 行数据,那么平均需要扫描的行为 n/2。因此当数据量增长时,这种方法的开销将显著增长。

扩展:oracle 索引 / oracle 创建索引 / oracle 删除索引

如果将一个已排序的值列(list of the values)划分为多个区间(range),每个区间的末尾包含指向下个区间的指针(pointer),而搜索树(search tree)中则保存指向每个区间的指针。此时在 n 行数据中查询一个值所需的时间为 log(n)。这就是 Oracle 索引的基本原理。

在一个平衡树索引(B-tree index)中,最底层的索引块(叶块(leaf block))存储了被索引的数据值,以及对应的 rowid。叶块之间以双向链表的形式相互连接。位于叶块之上的索引块被称为分支块(branch block),分枝块中包含了指向下层索引块的指针。如果被索引的列存储的是字符数据(character data),那么索引值为这些字符数据在当前数据库字符集(database character set)中的二进制值(binary value)。

对于唯一索引(unique index),每个索引值对应着唯一的一个 rowid。对于非唯一索引(nonunique index),每个索引值对应着多个已排序的 rowid。因此在非唯一索引中,索引数据是按照索引键(index key)及 rowid 共同排序的。键值(key value)全部为 NULL 的行不会被索引,只有簇索引(cluster index)例外。在数据表中,如果两个数据行的全部键值都为 NULL,也不会与唯一索引相冲突。

5.8.6.3 索引的属性

有两种类型的索引块:

用于搜索的分支块(branch block)

用于存储索引数据的叶块(leaf block)

5.8.6.3.1 分支块

分支块(branch block)中存储以下信息:

最小的键值前缀(minimum key prefix),用于在(本块的)两个键值之间做出分支选择

指向包含所查找键值的子块(child block)的指针()

包含 n 个键值的分支块(branch block)含有 n+1 个指针。键值及指针的数量同时还受索引块(index block)容量的限制。

5.8.6.3.2 叶块

所有叶块(leaf block)相对于其根分支块(root branch block)的深度(depth)是相同的。叶块用于存储以下信息:

数据行的键值(key value)

键值对应数据行的 ROWID

所有的 键值-ROWID 对(key and ROWID pair)都与其左右的兄弟节点(sibling)向链接(link),并按照(key,ROWID)的顺序排序。

5.8.6.4 平衡树结构的优势

平衡树数据结构(B-tree structure)具有以下优势:

平衡树(B-tree)内所有叶块(leaf block)的深度相同,因此获取索引内任何位置的数据所需的时间大致相同。

平衡树索引(B-tree index)能够自动保持平。

平衡树内的所有块容量平均在总容量的 3/4 左右。

在大区间(wide range)范围内进行查询时,无论匹配个别值(exact match)还是搜索一个区间(range search),平衡树都能提供较好的查询性能。

数据插入(insert),更新(update),及删除(delete)的效率较高,且易于维护键值的顺序(key order)

大型表,小型表利用平衡树进行搜索的效率都较好,且搜索效率不会因数据增长而降低。

5.8.7 索引唯一扫描

索引唯一扫描(index unique scan)是效率最高的数据访问方式之一。从平衡树索引(B-tree index)中获取数据时将采用此种方式。当一个唯一索引(采用平衡树结构)的全部列都包含在查询条件中,且查询体条件表达式均为等号(equality)时,优化器将选择使用索引唯一扫描。

5.8.8 索引区间扫描

当访问选择性较大的数据(selective data)时 Oracle 常进行索引区间扫描(index range scan)。扫描区间可以是封闭的(bounded)(两端均封闭),也可以是不封闭的(unbounded)(一端或两端均不封闭)。扫描所返回的数据按照索引列的升序进行排列,对于索引值相同的行将按 ROWID 的升序排列。

5.8.9 键压缩

用户利用键压缩(key compression)可以将索引或索引表(index-organized table)中键值(column value)的部分内容进行压缩,以便减少重复值带来的存储开销。

一般来说,索引的一个键(key)通常由两个片段(piece)构成:分组片段(grouping piece)及唯一片段(unique piece)。如果定义索引的键中不存在唯一片段,Oracle 会以 ROWID 的形式在此键的分组片段后添加一个唯一片段。键压缩(key compression)就是将键的分组片段从键中拆分出来单独存储,供多个唯一片段使用。

5.8.9.1 索引键的前缀和后缀

键压缩(key compression)将一个索引键拆分为前缀(prefix entry)(即分组片段(grouping piece))和后缀(suffix entry)(即唯一片段(unique piece))。压缩是通过一个索引块(index block)中的多个后缀共享一个前缀来实现的。在平衡树索引(B-tree index)中只有位于叶块(leaf block)的键会被压缩。在分支块(branch block)内不必存储键的后缀,因此其中的键也无需压缩。

键压缩(key compression)只能在每个索引块(index block)内分别实现,而不能跨多个索引块。压缩后每个索引行(index row)只保存后缀(suffix entry),而每个后缀将引用一个共享的前缀(prefix entry),后缀与其共享的前缀必须位于同一索引块内。

默认情况下,前缀(prefix entry)由除去最后一列之外的其他键列(key column)构成。例如,一个索引键(index key)由(column1,column2,column3)3 列构成,则默认的前缀为(column1, column2)。如一组索引值为(1,2,3),(1,2,4),(1,2,7),(1,3,5),(1,3,4),(1,4,4),则其中重复出现的前缀 (1,2),(1,3) 将被压缩。

用户也可以手工设定前缀长度(prefix length),即前缀所包含的列数。例如,如果用户设定前缀长度为 1,则在上述例子中,column1 为前缀,(column2,column3)为后缀,其中重复出现的前缀 1 将被压缩。

非唯一索引(nonunique index)的最大前缀长度(prefix length)为键列的个数,而唯一索引(unique index)的最大前缀长度为键列的个数减 1。

应用键压缩(key compression)后,生成索引时,如果一个键值(key value)的前缀(prefix entry)在索引块(index block)中不存在,此前缀才会被写入索引块中。一个前缀被写入后立即就可以被此索引块内的后缀(suffix entry)共享,直到所有引用此前缀的后缀都被删除为止。

扩展:oracle 索引 / oracle 创建索引 / oracle 删除索引

5.8.9.2 性能上及存储上的考虑

键压缩(key compression)能够节约大量存储空间,因此用户可以在一个索引块(index block)内存储更多的索引键(index key),从而减少 I/O,提高性能。

键压缩(key compression)能够减少索引所需的存储空间,但索引扫描时需要重构(reconstruct)键值(key value),因此增加了 CPU 的负担。此外键压缩也会带来一些存储开销,每个前缀(prefix entry)需要 4 字节(byte)的管理开销。

5.8.9.3 使用键压缩

键压缩(key compression)在多种情况下都能够发挥作用,例如:

对于非唯一索引(nonunique index),Oracle 会在每个重复的索引键(index key)之后添加 rowid 以便区分。如果使用了键压缩,在一个索引块(index block)内,Oracle 只需将重复的索引键作为前缀((prefix entry))存储一次,并用各行的 rowid 作为后缀(suffix entry)。

唯一索引(nonunique index)中也存在相同的情况。例如唯一索引(stock_ticker,transaction_time)的含义是(项目,时间戳),通常数千条记录中stock_ticker 的值是相同的,但她们对应的 transaction_time 值各不相同。使用了键压缩后,一个索引块中每个 stock_ticker 值作为前缀只需存储一次,而各个transaction_time 值则作为后缀存储,并引用一个共享的 stock_ticker 前缀。

在一个包含 VARRAY 或 NESTED TABLE 数据类型(datatype)的索引表(index-organized table)中,这些collection 类型中各个元素(element)的对象标识符(object identifier)是重复的。用户可以使用键压缩以避免重复存储这些对象标识符。

有些情况无法使用键压缩(key compression)。例如,一个只有一个索引键(index key)的唯一索引(unique index)就无法使用键压缩,因为索引键中不存在可供共享的分组片段(grouping piece)。

5.8.10 逆序键索引

用户可以创建逆序键索引(reverse key index),此处的逆序指索引列值(index key value)得各个字节(byte)按倒序排列,而非索引列(index key)逆序排列。在 RAC 环境中,使用这样的排列方式可以避免由于对索引的修改集中在一小部分叶块(leaf block)上而造成的性能下降。通过使索引的键值逆序排列,可以使插入操作分布在索引的全部叶块中。

使用逆序键索引(reverse key index)后将无法对此索引进行索引区间扫描(index range scanning),因为在逆序键索引 中,词汇上(lexically)相邻的索引键(index key)在存储上未必相邻。因此在逆序键索引 上只能进行确定键扫描(fetch-by-key scan)或全索引扫描(full-index scan)。

有些情况下,使用逆序键索引(reverse key index)可以令 RAC 环境下的 OLTP 应用效率更高。例如,为一个 e-mail 应用中的所有邮件进行索引:由于用户可能保存旧的邮件,因此索引必须做到既能快速访问最新邮件,也能快速访问旧邮件。

用户使用 REVERSE 就可以轻易地创建逆序键索引(reverse key index)。在 CREATE INDEX语句中使用 REVERSE 关键字作为创建索引的选项:

CREATE INDEX i ON t (a,b,c) REVERSE;

用户也可以在 REBUILD 子句后添加 NOREVERSE 关键字将一个逆序键索引(reverse key index)转换为常规的索引:

ALTER INDEX i REBUILD NOREVERSE;

如果 REBUILD 子句后没有使用 NOREVERSE 关键字,那么逆序键索引(reverse key index)被重建后仍将保持逆序。

5.8.11 位图索引

索引的目标是为用户提供指向包含特定键值(key value)的数据行的指针。在常规的索引中,Oracle 将各行的键值及与此键值对应的一组 ROWID 存储在一起,从而实现了上述目标。而在位图索引(bitmap index)中,只需存储每个键值的位图(bitmap),而非一组 ROWID。

位图(bitmap)中的每一位(bit)对应一个可能的 ROWID。如果某一位被置位(set),则表明着与此位对应的 ROWID 所指向的行中 包含此位所代表的键值(key value)。Oracle 通过一个映射函数(mapping function)将位信息转化为实际的 ROWID,因此虽然位图索引(bitmap index)内部的存储结构与常规索引不同,但她同样能实现常规索引的功能。当不同值的索引键的数量较少时,位图索引的存储效率相当高。

如果在 WHERE 子句内引用的多个列上都建有位图索引(bitmap index),那么进行位图索引扫描时(bitmap indexing)可以将各个位图索引融合在一起。不满足全部条件的行可以被预先过滤掉。因此使用位图索引能够极大地提高查询的响应时间。

5.8.11.1 数据仓库应用中位图索引的优势

数据仓库应用(data warehousing application)的特点是数据量巨大,执行的多为自定义查询(ad hoc query),且并发事务较少。这种环境下使用位图索引(bitmap index)具备如下优势:

能够减少大数据量自定义查询的响应时间

与其他索引技术相比能够节省大量存储空间

即使硬件配置较低也能显著提高性能

有利于并行 DML 和并行加载

为一个大表建立传统的平衡树索引(B-tree index)可能占用极大的存储空间,索引有可能比数据表还要大数倍。而一个位图索引(bitmap index)所占的空间比被索引数据还要小得多。

位图索引(bitmap index)不适用于 OLTP系统,因为这样的系统中存在大量对数据进行修改的并发事务。位图索引主要用于数据仓库系统中(data warehousing)的决策支持功能,在这种环境下用户对数据的操作主要是查询而非修改。

主要进行大于(greater than)或小于(less than)比较的列,不适宜使用位图索引(bitmap index)。例如,WHERE 子句中常会将 salary 列和一个值进行比较,此时更适合使用平衡树索引(B-tree index)。位图索引适用于等值查询,尤其是存在 AND,OR,和 NOT 等逻辑操作符的组合时。

位图索引(bitmap index)是集成在 Oracle 的优化器(optimizer)和执行引擎(execution engine)之中的。位图索引也能够和 Oracle 中的其他执行方法(execution method)无缝地组合。例如,优化器可以在利用一个表的位图索引和另一个表的平衡树索引(B-tree index)对这两张表进行哈希连接(hash join)。优化器能够在位图索引及其他可用的访问方法(例如常规的平衡树索引,或全表扫描(full table scan))中选择效率最高的方式,同时考虑是否适合使用并行执行。

扩展:oracle 索引 / oracle 创建索引 / oracle 删除索引

位图索引(bitmap index)如同常规索引一样,可以结合并行查询(parallel query)和并行 DML(parallel DML)一起工作。建立于分区表(partitioned table)的位图索引必须为本地索引(local index)。Oracle 还支持并行地创建位图索引,以及创建复合位图索引。

5.8.11.2 基数

在基数(cardinality)小的列上建立位图索引(bitmap index)效果最好。所谓某列的基数小(low cardinality)是指此列中所有不相同的值的个数要小于总行数。如果某列中所有不相同的值的个数占总行数的比例小于 1%,或某列中值的重复数量在 100 个以上,那么就可以考虑在此列上建立位图索引。即便某列的基数较上述标准稍大,或值的重复数量较上述标准稍小,如果在一个查询的 WHERE 子句中需要引用此列定义复杂的条件,也可以考虑在此列上建立位图索引。

例如,一个表包含一百万行数据,其中的一列包含一万个不相同的值,就可以考虑在此列上创建位图索引(bitmap index)。此列上位图索引的查询性能将超过平衡树索引(B-tree index),当此列与其他列作为组合条件时效果尤为明显。

平衡树索引(B-tree index)适用于高基数的数据,即数据的可能值很多,例如CUSTOMER_NAME 或 PHONE_NUMBER 列。在有些情况下,平衡树索引所需的存储空间可能比被索引数据还要大。如果使用得当,位图索引将远远小于同等情况下的平衡树索引。

对于自定义查询(ad hoc query)或相似的应用,使用位图索引(bitmap index)能够显著地提高查询性能。查询的 WHERE 子句中的 AND 和 OR 条件直接对位图(bitmap)进行布尔运算(Boolean operation)得到一个位图结果集(resulting bitmap),而无需将所有的位图转换为 ROWID。如果布尔操作后的结果集较小,那么查询就能够迅速得到结果,而无需进行全表扫描(full table scan)。

5.8.11.3 位图索引和空值

与其他大多数索引不同,位图索引(bitmap index)可以包含键值(key value)为 NULL 的行。将键值为空的行进行索引对有些 SQL 语句是有用处的,例如包含 COUNT 聚合函数的查询。

5.8.11.4 分区表上的位图索引

用户可以在分区表(partitioned table)上创建位图索引(bitmap index)。唯一的限制是位图索引对分区表来说必须是本地的(local),而不能是全局索引(global index)。只有非分区表才能使用全局位图索引。

5.8.12 位图连接索引

除了建立在单个表之上的位图索引(bitmap index),用户还可以创建位图连接索引(bitmap join index),此种索引是为了连接(join)两个或多个数据表而建的。位图连接索引(bitmap join index)可以预先将有连接关系的数据进行保存,且所需的存储空间较小。对于一个表的某列的每个值,位图连接索引为其保存其他表中与此值有连接关系的数据行的 rowid。在数据仓库环境中,连接关系通常是维表(dimension table)中的主键(primary key)与事实表(fact table)中的外键(foreign key)进行等值内连接(equi-inner join)。

物化连接视图(materialized join view)也是一种预先将连接物化的方法,但与之相比位图连接索引(bitmap join index)所需的存储空间更少。因为物化连接视图不会压缩事实表(fact table)中的 rowid。

扩展:oracle 索引 / oracle 创建索引 / oracle 删除索引

四 : Oracle位图索引

Oracle位图索引

假设一个100W行的表有一个字段会频繁地被当做查询条件,我们会想到在这一列上面建立一个索引。但是这一列只可能取3个值。那么如果建立一个B*树索引(普通索引)是不行的,因为无论查找哪一个值,都可能会查出很多数据。那么位图索引就会很适合了。

如果我们在emp表的job列建立一个位图索引:

Sql代码 www.2cto.com

create BITMAP index job_idx on emp(job);

oracle在索引中存储的内容可能是这样的:

位图索引 Oracle位图索引

ANALYST,CLERK,MANAGER,PERSIDENT,SALESMAN这是job列所有可能取的值,上面只列举了9行,可能有10多W行。1代表取该值,0代表不取,比如第八行取值为ANALYST,第一行为CLERK。这个时候,如果我们想查找值为CLERK的所有行数据,很容易就查得出来。

位图索引使用场景

位图索引对于相异基数低的数据最为合适,相异基数低是相对而言,4000行的数据,2是相异基数。只有2行的表,1当然不是相异基数。也就是如果某一列只可能取几个值,而且这个表的数据量又比较大,那么这一列就适合建立一个位图索引。 www.2cto.com

对于数据仓库和即席查询,一般使用位图索引。另外,位图索引适合读密度高的系统,不适合写高密度的系统。因为修改一行,就会锁定上面的位图索引所指向的上所有行数据(可能好几百行)。因为位图索引的一个索引指向的是多行数据,而不是像普通索引那样只指向一行数据。

扩展:oracle索引 / 位图索引 / oracle创建位图索引

本文标题:oracle索引-Oracle之索引(Index)实例讲解 - 基础
本文地址: http://www.61k.com/1101167.html

61阅读| 精彩专题| 最新文章| 热门文章| 苏ICP备13036349号-1