转载oracle索引详解2

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了转载oracle索引详解2相关的知识,希望对你有一定的参考价值。

原文URL:http://justplayoop1.iteye.com/blog/1259562

一. 索引介绍

 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 <> ‘aa‘;          把上面的语句改成如下的查询语句,这样,在采用基于规则的优化器而不是基于代价的优化器(更智能)时,将会使用索引。            select cust_Id,cust_name from customers where cust_rating < ‘aa‘ or cust_rating > ‘aa‘;    特别注意:通过把不等于操作符改成 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)=‘01-MAY-81‘;     把上面的语句改成下面的语句,这样就可以通过索引进行查找。  select empno,ename,deptno from emp where  hiredate<(to_date(‘01-MAY-81‘)+0.9999);

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

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

  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 =‘990354‘;

特别注意: 不匹配的数据类型之间比较会让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  特点  

  1. 适合与大量的增、删、改(OLTP )
  2.  不能用包含OR 操作符的查询;
  3.  适合高基数的列(唯一值多)
  4.  典型的树状结构;
  5.  每个结点都是数据块;
  6.  大多都是物理上一层、两层或三层不定,逻辑上三层;
  7.  叶子块数据是排序的,从左向右递增;
  8.  在分支块和根块中放的是索引的范围;

 

2.2  位图索引  位图索引非常适合于决策支持系统(Decision Support System , DSS) 和数据仓库 ,它们不应该用于通过事务处理应用程序访问的表。它们可以使用较少到中等基数( 不同值的数量 ) 的列访问非常大的表。尽管位图索引最多可达 30 个列,但通常它们都只用于少量的列。  例如,您的表可能包含一个称为Sex 的列,它有两个可能值:男和女。这个基数只为 2 ,如果用户频繁地根据 Sex列的值查询该表,这就是位图索引的基列。当一个表内包含了多个位图索引时,您可以体会到位图索引的真正威力。如果有多个可用的位图索引, Oracle 就可以合并从每个位图索引得到的结果集,快速删除不必要的数据。

Bitmap t 特点  

  1. 适合与决策支持系统;
  2.  做UPDATE 代价非常高;
  3.  非常适合OR 操作符的查询;
  4.  基数比较少的时候才能建位图索引;

技巧: 对于有较低基数的列需要使用位图索引。性别列就是这样一个例子,它有两个可能值:男或女( 基数仅为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 语句不会受到这种锁定问题的影响。  位图索引 的使用 限制 :

  1. 基于规则的优化器不会考虑位图索引。
  2. 当执行ALTER TABLE 语句并修改包含有位图索引的列时,会使位图索引失效。
  3.  位图索引不包含任何列数据,并且不能用于任何类型的完整性检查。
  4.  位图索引不能被声明为唯一索引。
  5.  位图索引的最大长度为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 语句的性能也同样得以提高, 这是因为行在物理上有序。由于键列的值在表和索引中都没有重复, 存储所需要的空间也随之减少。  如果不会频繁地根据主键列查询数据,则需要在索引组织表中的其他列上创建二级索引。不会频繁根据主键查询表的应用程序不会了解到使用索引组织表的全部优点。 对于总是通过对主键的精确匹配或范围扫描进行访问的表,就需要考虑使用索引组织表。  技巧: 可以在索引组织表上建立二级索引。  2.5  反转键索引  当载入一些有序数据时,索引肯定会碰到与I/O 相关的一些瓶颈。在数据载入期间,某部分索引和磁盘肯定会比其他部分使用频繁得多。为了解决这个问题,可以把索引表空间存放在能够把 文件物理分割在多个磁盘上的磁盘体系结构上 。  为了解决这个问题,Oracle 还提供了一种反转键索引的方法。如果数据以反转键索引存储,这些数据的值就会与原先存储的数值相反。这样,数据 1234 、 1235 和 1236 就被存储成 4321 、 5321 和 6321 。 结果就是索引会为每次新插入的行更新不同的索引块。  技巧: 如果您的磁盘容量有限,同时还要执行大量的有序载入,就可以使用反转键索引。  不可以将反转键索引与位图索引或索引组织表结合使用。 因为 不能对位图索引和索引组织表进行反转键处理。  2.6  基于函数的索引  可以在表中创建基于函数的索引。如果没有基于函数的索引,任何在列上执行了函数的查询都不能使用这个列的索引。例如,下面的查询就不能使用JOB 列上的索引,除非它是基于函数的索引:  select *   from emp   where UPPER(job) = ‘MGR‘;  下面的查询使用JOB 列上的索引,但是它将不会返回 JOB 列具有 Mgr 或 mgr 值的行:  select *   from emp   where job = ‘MGR‘;

可以创建这样的索引,允许索引访问支持基于函数的列或数据。可以对列表达式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索引详解2的主要内容,如果未能解决你的问题,请参考以下文章

Oracle中的索引详解(转载)

Oracle 复合索引--转载

Oracle索引详解

JAVA通过JDBC连接Oracle数据库详解转载

Oracle索引详解

oracle树状索引详解(图摘取《收获不止oracle》)