Oracle中索引的创建和使用

您所在的位置:网站首页 oracle索引的建立与使用 Oracle中索引的创建和使用

Oracle中索引的创建和使用

#Oracle中索引的创建和使用| 来源: 网络整理| 查看: 265



OLTP系统索引创建

创建索引的作用

1、通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。 2、可以大大加快数据的检索速度,这也是创建索引的最主要的原因。 3、可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。 4、使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间。

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

如何选择索引列 一、应该建索引列的特点

1)在经常需要搜索的列上,可以加快搜索的速度; 2)在作为主键的列上,强制该列的唯一性和组织表中数据的排列结构; 3)在经常用在连接的列上,这些列主要是一些外键,可以加快连接的速度;

4)在经常需要根据范围进行搜索的列上创建索引,因为索引已经排序,其指定的范围    是连续的; 5)在经常需要排序的列上创建索引,因为索引已经排序,这样查询可以利用索引的排序,加快排序查询时间; 6)在经常使用在WHERE子句中的列上面创建索引,加快条件的判断速度。

二、不应该建索引列的特点

1)对于那些在查询中很少使用或者参考的列不应该创建索引。这是因为,既然这些列很少使用到,因此有索引或者无索引,并不能提高查询速度。相反,由于增加了索引,反而 降低了系统的维护速度和增大了空间需求。 2)对于那些只有很少数据值的列也不应该增加索引。这是因为,由于这些列的取值很少,例如人事表的性别列,在查询的结果中,结果集的数据行占了表中数据行的很大比例,即需要在表中搜索的数据行的比例很大。增加索引,并不能明显加快检索速度。 3)对于那些定义为blob数据类型的列不应该增加索引。这是因为,这些列的数据量要么相当大,要么取值很少。 4)当修改性能远远大于检索性能时,不应该创建索引。这是因为,修改性能和检索性能是互相矛盾的。当增加索引时,会提高检索性能,但是会降低修改性能。当减少索引时,会提高修改性能,降低检索性能。因此,当修改性能远远大于检索性能时,不应该创建索引。(数据量庞大,考虑创建分区索引)

索引的创建语法

CREATEUNIUQE | BITMAP INDEX . ON . ( | ASC | DESC, | ASC | DESC,...) TABLESPACE STORAGE LOGGING | NOLOGGING COMPUTE STATISTICS NOCOMPRESS | COMPRESS NOSORT | REVERSE PARTITION | GLOBAL PARTITION

相关说明 1) UNIQUE | BITMAP:指定 UNIQUE为唯一值索引, BITMAP为位图索引,省略为 B-Tree索引。 2) | ASC | DESC:可以对多列进行联合索引,当为 expression 时即―基于函数的索引 3) TABLESPACE:指定存放索引的表空间(索引和原表不在一个表空间时效率更高) 4) STORAGE:可进一步设置表空间的存储参数 5) LOGGING | NOLOGGING:是否对索引产生重做日志(对大表尽量使用 NOLOGGING 来减少占用空间并提高效率) 6) COMPUTESTATISTICS:创建新索引时收集统计信息 7) NOCOMPRESS | COMPRESS:是否使用―键压缩‖(使用键压缩可以删除一个键列 中出现的重复值) 8) NOSORT | REVERSE: NOSORT 表示与表中相同的顺序创建索引, REVERSE表示相 反顺序存储索引值 9) PARTITION | NOPARTITION:可以在分区表和未分区表上对创建的索引进行分区

索引使用误区 限制索引

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

1、使用不等于操作符( 、 !=)

  下面的查询即使在cust_rating列有一个索引,查询语句仍然执行一次全表扫描。     select cust_Id,cust_name from customers wherecust_rating 'aa';    把上面的语句改成如下的查询语句,这样,在采用基于规则的优化器而不是基于代价的优化器(更智能)时,将会使用索引。    select cust_Id,cust_name fromcustomers where cust_rating 'aa';

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

2、 使用 IS NULL或 IS NOT NULL

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

3、使用函数

如果不使用基于函数的索引,那么在 SQL语句的 WHERE子句中对存在索引的列使用函数时,会使优化器忽略掉这些索引。 下面的查询不会使用索引(只要它不是基于函数的索引) select empno,ename,deptno from emp where trunc(hiredate)='01-MAY-81'; 把上面的语句改成下面的语句,这样就可以通过索引进行查找。 select empno,ename,deptno from emp where hiredate 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环境中使用位图索引

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索引在有限制条件(需要指定一个确定的值而不是一个值范围)的情 况下非常有用

索引组织表

索引组织表会把表的存储结构改成B树结构,以表的主键进行排序。这种特 殊的表和其他类型的表一样,可以在表上执行所有的DML和DDL语句。由于 表的特殊结构, ROWID并没有被关联到表的行上。 对于一些涉及精确匹配和范围搜索的语句,索引组织表提供了一种基于键的 快速数据访问机制。基于主键值的UPDATE和DELETE语句的性能也同样得以 提高, 这是因为行在物理上有序。由于键列的值在表和索引中都没有重复,存储所需要的空间也随之减少。 如果不会频繁地根据主键列查询数据,则需要在索引组织表中的其他列上创 建二级索引。不会频繁根据主键查询表的应用程序不会了解到使用索引组织表的 全部优点。 对于总是通过对主键的精确匹配或范围扫描进行访问的表,就需要考 虑使用索引组织表。

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

反转键索引

当载入一些有序数据时,索引肯定会碰到与I/O相关的一些瓶颈。在数据载 入期间,某部分索引和磁盘肯定会比其他部分使用频繁得多。为了解决这个问题, 可以把索引表空间存放在能够把文件物理分割在多个磁盘上的磁盘体系结构上。 为了解决这个问题,Oracle还提供了一种反转键索引的方法。如果数据以反 转键索引存储,这些数据的值就会与原先存储的数值相反。这样,数据1234、 1235和1236就被存储成4321、5321和6321。结果就是索引会为每次新插入 的行更新不同的索引块。 技巧:如果您的磁盘容量有限,同时还要执行大量的有序载入,就可以使用 反转键索引。 不可以将反转键索引与位图索引或索引组织表结合使用。 因为不能对位图索 引和索引组织表进行反转键处理。

基于函数的索引

可以在表中创建基于函数的索引。如果没有基于函数的索引,任何在列上执 行了函数的查询都不能使用这个列的索引。例如,下面的查询就不能使用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!!!

分区索引

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

每个类型都有两个子类型,有前缀索引和无前缀索引。表各列上的索引可以有各种类型索引的组合。 如果使用了位图索引,就必须是本地索引。把索引分区最主要的原因是可以减少 所需读取的索引的大小,另外把分区放在不同的表空间中可以提高分区的可用性 和可靠性。在使用分区后的表和索引时,Oracle还支持并行查询和并行DML。这样就可以同时执行多个进程,从而加快处理这条语句。

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

可以使用与表相同的分区键和范围界限来对本地索引分区。每个本地索引的 分区只包含了它所关联的表分区的键和ROWID。本地索引可以是B树或位图索 引。如果是 B树索引,它可以是唯一或不唯一的索引。 这种类型的索引支持分区独立性,这就意味着对于单独的分区,可以进行增 加、截取、删除、分割、脱机等处理,而不用同时删除或重建索引。Oracle自 动维护这些本地索引。本地索引分区还可以被单独重建,而其他分区不会受到影 响。 (1) 有前缀的索引 有前缀的索引包含了来自分区键的键,并把它们作为索引的前导。例如,让 我们再次回顾 participant表。在创建该表后,使用survey_id和survey_date这 两个列进行范围分区,然后在survey_id列上建立一个有前缀的本地索引,如下图所示。这个索引的所有分区都被等价划分,就是说索引的分区都使用表的相同 范围界限来创建。

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

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

 

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

 

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

全局分区索引

全局分区索引在一个索引分区中包含来自多个表分区的键。一个全局分区索 引的分区键是分区表中不同的或指定一个范围的值。在创建全局分区索引时,必 须定义分区键的范围和值。 全局索引只能是B树索引。Oracle在默认情况下不会维护全局分区索引。 如果一个分区被截取、增加、分割、删除等,就必须重建全局分区索引,除非在 修改表时指定 ALTER TABLE命令的UPDATE GLOBAL INDEXES子句。 (2) 有前缀的索引 通常,全局有前缀索引在底层表中没有经过对等分区。没有什么因素能限制 索引的对等分区,但Oracle在生成查询计划或执行分区维护操作时,并不会充 分利用对等分区。如果索引被对等分区,就必须把它创建为一个本地索引,这样 Oracle可以维护这个索引,并使用它来删除不必要的分区,如下图所示。在该 图的 3个索引分区中,每个分区都包含指向多个表分区中行的索引条目。

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

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

位图连接索引

位图连接索引是基于两个表的连接的位图索引,在数据仓库环境中使用这种索引改进连接维度表和事实表的查询的性能。创建位图连接索引时,标准方法是 连接索引中常用的维度表和事实表。当用户在一次查询中结合查询事实表和维度 表时,就不需要执行连接,因为在位图连接索引中已经有可用的连接结果。通过 压缩位图连接索引中的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数据库中索引创建的一些知识的介绍和关键点。需要读懂理解之后结合系统业务情况合理创建索引,以求达到预期性能。

本文部分内容摘自《Oracle超详细讲解.pdf》



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3