Oracle——03索引

Oracle——03索引


Oracle 索引 详解

创建Oracle索引的标准语法:
CREATE INDEX 索引名 ON 表名 (列名)
     TABLESPACE 表空间名;
创建唯一索引:
CREATE unique INDEX 索引名 ON 表名 (列名)
     TABLESPACE 表空间名;
创建组合索引:
CREATE INDEX 索引名 ON 表名 (列名1,列名2)
     TABLESPACE 表空间名;
创建反向键索引:
CREATE INDEX 索引名 ON 表名 (列名) reverse
     TABLESPACE 表空间名;

1、明确地创建索引
  create index index_name on table_name(field_name)
  tablespace tablespace_name
  pctfree 5
  initrans 2
  maxtrans 255
  storage
  (
  minextents 1
  maxextents 16382
  pctincrease 0
  );
  2、创建基于函数的索引
  常用与UPPER、LOWER、TO_CHAR(date)等函数分类上,例:
  create index idx_func on emp(UPPER(ename)) tablespace tablespace_name;
  3、创建位图索引
  对基数较小,且基数相对稳定的列建立索引时,首先应该考虑位图索引,例:
  create bitmap index idx_bitm on class (classno) tablespace tablespace_name;
  4、明确地创建唯一索引
  可以用create unique index语句来创建唯一索引,例:
  create unique index dept_unique_idx on dept(dept_no) tablespace idx_1;
  5、创建与约束相关的索引
  可以用using index字句,为与unique和primary key约束相关的索引,例:
  alter table table_name
  add constraint PK_primary_keyname primary key(field_name)
  using index tablespace tablespace_name;
  如何创建局部区索引?
  1)基础表必须是分区表
  2)分区数量与基础表相同
  3)每个索引分区的子分区数量与相应的基础表分区相同
  4)基础表的自分区中的行的索引项,被存储在该索引的相应的自分区中,例如
  create index TG_CDR04_SERV_ID_IDX on TG_CDR04(SERV_ID)
  Pctfree 5
  Tablespace TBS_AK01_IDX
  Storage(
  MaxExtents 32768
  PctIncrease 0
  FreeLists 1
  FreeList Groups 1
  )
  local
  /
  如何创建范围分区的全局索引?
  基础表可以是全局表和分区表
  create index idx_start_date on tg_cdr01(start_date)
  global partition by range(start_date)
  (partition p01_idx vlaues less than ('0106')
  partition p01_idx vlaues less than ('0111')
  ...
  partition p01_idx vlaues less than ('0401'))
  /
  如何重建现存的索引?
  重建现存的索引的当前时刻不会影响查询
  重建索引可以删除额外的数据块
  提高索引查询效率
  alter index idx_name rebuild nologging;
  对于分区索引
  alter index idx_name rebuild partition partition_name nologging;
  删除索引的原因?
  1)不再需要的索引
  2)索引没有针对其相关的表所发布的查询提供所期望的性能改善
  3)应用没有用该索引来查询数据
  4)该索引无效,必须在重建之前删除该索引
  5)该索引已经变的太碎了,必须在重建之前删除该索引
  语句:
  drop index idx_name;
  drop index idx_name partition partition_name;
  建立索引的代价?
  基础表维护时,系统要同时维护索引,不合理的索引将严重影响系统资源,
  主要表现在CPU和I/O上。
  插入、更新、删除数据产生大量db file sequential read锁等待。

1.重建索引
alter index index_name1 rebuild;

2.重建索引并转移到别的表空间
alter index index_name1 rebuild tablespace other_tablespace;  --这个表空间要首先创建

3.修改索引的一些参数设置
alter index index_name rebuild pctfree 30 storage(next 100k);

4.自动为索引分配空间
alter index index_name allocate extent;

5.整合索引碎片
alter index index_name coalesce;

6.删除一个索引
drop index index_name;

7.开启对索引的监控,然后分析索引
--首先开启对索引的监控
alter index index_name  monitoring usage;
--然后执行一个与索引有关的查询
--接着关闭对索引的监控
alter index index_name  nomonitoring usage;
--然后查询v$object_usage视图
select index_name,start_monitoring,end_monitoring
from  v$object_usage
where index_name = '........'

一、重建索引的前提
1、表上频繁发生update,delete操作;
2、表上发生了alter table ..move操作(move操作导致了rowid变化)。

二、重建索引的标准
1、索引重建是否有必要,一般看索引是否倾斜的严重,是否浪费了空间, 那应该如何才可以判断索引是否倾斜的严重,是否浪费了空间, 对索引进行结构分析(如下):
SQL>Analyze index index_name validate structure;

2、在执行步骤1的session中查询index_stats表,不要到别的session去查询。
SQL>select height,DEL_LF_ROWS/LF_ROWS from index_stats;
说明:当 查询出来的 height>=4 或者 DEL_LF_ROWS/LF_ROWS>0.2 的场合 , 该索引考虑重建 。

举例: (t_gl_assistbalance 26 万多条信息 )
SQL> select count(*) from t_gl_assistbalance ;
输出结果:
COUNT(*)
----------
265788

SQL> Analyze index IX_GL_ASSTBAL_1 validate structure;
Index analyzed

SQL> select height,DEL_LF_ROWS/LF_ROWS from index_stats;
输出结果:
HEIGHT DEL_LF_ROWS/LF_ROWS
---------- -------------------
4 1

三、重建索引的方式
1、drop 原来的索引,然后再创建索引;
举例:
删除索引:drop index IX_PM_USERGROUP;
创建索引:create index IX_PM_USERGROUP on T_PM_USER (fgroupid);
说明:此方式耗时间,无法在24*7环境中实现,不建议使用。

2 、直接重建:
举例:
alter index indexname rebuild; 或alter index indexname rebuild online;
说明:此方式比较快,可以在24*7环境中实现,建议使用此方式。

四、alter index rebuild 内部过程和注意点
alter index rebuild 和alter index rebuil online的区别
1、扫描方式不同
1.1、Rebuild以index fast full scan(or table full scan) 方式读取原索引中的数据来构建一个新的索引,有排序的操作;

1.2、rebuild online 执行表扫描获取数据,有排序的操作;
说明:Rebuild 方式 (index fast full scan or table full scan 取决于统计信息的cost)
举例1
SQL> explain plan for alter index IX_GL_ASSTBAL_1 rebuild;

Explained
SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT

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

| Id | Operation | Name | Rows | Bytes | Cost |

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

| 0 | ALTER INDEX STATEMENT | | 999K| 4882K| 3219 |

| 1 | INDEX BUILD NON UNIQUE| IDX_POLICY_ID2 | | | |

| 2 | SORT CREATE INDEX | | 999K| 4882K| |

| 3 | INDEX FAST FULL SCAN | IDX_POLICY_ID2 | 999K| 4882K| |

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

举例2
SQL> explain plan for alter index idx_policy_id rebuild;

Explained

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT

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

| Id | Operation | Name | Rows | Bytes | Cost |

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

| 0 | ALTER INDEX STATEMENT | | 2072K| 9M| 461 |

| 1 | INDEX BUILD NON UNIQUE| IDX_POLICY_ID | | | |

| 2 | SORT CREATE INDEX | | 2072K| 9M| |

| 3 | TABLE ACCESS FULL | TEST_INDEX | 2072K| 9M| 461 |

举例3 ( 注意和 举例1 比较 )
Rebuil online 方式 :
SQL> explain plan for alter index idx_policy_id2 rebuild online;

Explained
SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT

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

| Id | Operation | Name | Rows | Bytes | Cost |

---------------------------------------------------------------------| 0 | ALTER INDEX STATEMENT | | 999K| 4882K| 3219 |

| 1 | INDEX BUILD NON UNIQUE| IDX_POLICY_ID2 | | | |

| 2 | SORT CREATE INDEX | | 999K| 4882K| |

| 3 | TABLE ACCESS FULL | TEST_INDEX2 | 999K| 4882K| 3219 |

2 、rebuild 会阻塞 dml 操作 ,rebuild online 不会阻塞 dml 操作 ;

3 、rebuild online 时系统会产生一个 SYS_JOURNAL_xxx 的 IOT 类型的系统临时日志表 , 所有 rebuild online 时索引的变化都记录在这个表中 , 当新的索引创建完成后 , 把这个表的记录维护到新的索引中去 , 然后 drop 掉旧的索引 ,rebuild online 就完成了。

注意点:
1、 执行rebuild操作时,需要检查表空间是否足够;
2、虽然说rebuild online操作允许dml操作,但是还是建议在业务不繁忙时间段进行;

Rebuild操作会产生大量redo log ;
五、重建分区表上的分区索引
重建分区索引方法:
Alter index indexname rebuild partition paritionname tablespace tablespacename;

Alter index indexname rebuild subpartition partitioname tablespace tablespacename;

Partition name 可以从user_ind_partitions查找
Tablepace 参数允许alter index操作更改索引的存储空间;

六、索引状态描述
在数据字典中查看索引状态,发现有三种:
valid:当前索引有效
N/A :分区索引 有效
unusable:索引失效
七、术语
1、高基数:简单理解就是表中列的不同值多。
2、低基数:建单理解就是表中的列的不同值少。
3、以删除的叶节点数量:指得是数据行的delete操作从逻辑上删除的索引节点 的数量,要记住oracle在删除数据行后,将 “ 死 “ 节点保留在索引中,这样做可以加快sql删除操作的速度,因此oracle删除数据行后可以不必重新平衡索引。

4、索引高度:索引高度是指由于数据行的插入操作而产生的索引层数,当表中添加大量数据时,oracle将生成索引的新层次以适应加入的数据行,因此,oracle索引可能有4层,但是这只会出现在索引数中产生大量插入操作的区域。Oracle索引的三层结构可以支持数百万的项目,而具备4层或是更多层的需要重建。
5、每次索引访问的读取数:是指利用索引读取一数据行时所需要的逻辑I/O操作数,逻辑读取不必是物理读取,因为索引的许多内容已经保存在数据缓冲区,然而,任何数据大于10的索引都需要重建。

6、什么时候重建呢?
察看 dba_indexes 中的 blevel 。这列是说明索引从根块到叶快的级别,或是深度。如果级别大于等于4。则需要重建,

如下 :Select index_name,blevel from dba_indexes where blevel>=4.
另一个从重建中受益的指标显然是当该索引中的被删除项占总的项数的百分比。如果在20%以上时,也应当重建,如下

SQL>analyze index index_name validate structure

SQL>select (del_lf_rows_len/lf_rows_len)*100 from index_stats where name= ’ index_name ’

就能看到是否这个索引被删除的百分比。
7、什么样的重建方式更好?
(1)、建索引的办法:
1.1、删除并从头开始建立索引。
1.2 、 使用 alter index index_name rebuild 命令重建索引。
1.3 、 使用 alter index index_name coalesce 命令重建索引。
(2)、下面讨论一下这三种方法的优缺点:

2.1、删除并从头开始建索引:方法是最慢的,最耗时的。一般不建议。

2.2、Alter index index_name rebuild
快速重建索引的一种有效的办法,因为使用现有索引项来重建新索引,如果客户操作时有其他用户在对这个表操作,尽量使用带online参数来最大限度的减少索引重建时将会出现的任何加锁问题,alter index index_name rebuild online。

但是,由于新旧索引在建立时同时存在,因此,使用这种技巧则需要有额外的磁盘空间可临时使用,当索引建完后把老索引删除,如果没有成功,也不会影响原来的索引。利用这种办法可以用来将一个索引移到新的表空间。

Alter index index_name rebuild tablespace tablespace_name 。
这个命令的执行步骤如下:
首先,逐一读取现有索引,以获取索引的关键字。
其次,按新的结构填写临时数据段。
最后,一旦操作成功,删除原有索引树,降临时数据段重命名为新的索引。

需要注意的是alter index index_name rebuild 命令中必须使用tablespace字句,以保证重建工作是在现有索引相同的表空间进行。

2.3、alter index index_name coalesce
使用带有coalesce参数时重建期间不需要额外空间,它只是在重建索引时将处于同一个索引分支内的叶块拼合起来,这最大限度的减少了与查询过程中相关的潜在的加锁问题,但是,coalesce选项不能用来将一个索引转移到其他表空间。

八、其他
1、truncate 分区操作和truncate 普通表的区别?
1.1、Truncate 分区操作会导致全局索引失效; truncate 普通表对索引没有影响;

1.2、Truncate 分区操作不会释放全局索引中的空间,而truncate 普通表会释放索引所占空间;

2、rename 表名操作对索引没有影响,因为rename操作只是更改了数据字典,表中数据行的rowid并没有发生变化

总结:
1、判断是否需要重建索引:
SQL>analyze index index_name validate structure;

SQL> select height,DEL_LF_ROWS/LF_ROWS from index_stats;

( 或 Select index_name,blevel from dba_indexes where blevel>=4 );

说明 : 当查询出来的 height>=4 或者 DEL_LF_ROWS/LF_ROWS>0.2 的场合 , 该索引考虑重建 ;

2 、重建索引方法 :
方法一、
Alter index index_name rebuild tablespace tablespace_name;
优点:是快速重建索引的一种有效的办法,可以用来将一个索引移到新的表空间。
缺点:重建期间需要额外空间。

方法二、
alter index index_name coalesce;
优点:重建期间不需要额外空间。
缺点:coalesce选项不能用来将一个索引转移到其他表空间。


索引的三大特点:
1.索引数的高度一般较低
2.索引由索引列存储的值及rowid组成
 索引SELECT * FROM T WHERE ID = 1会导致索引回表的产生,若不需要看全部数据可用SELECT ID FROM T WHERE ID= 1或可建多列的复核索引,但是复核索引最好不要超过3列的复核。在更新操作不频繁的情况下可考虑使用索引组织表
3.索引本身是有序的
 减少ORDER BY、DISTINCT排序所浪费的COST

聚合因子:
建立索引的列的顺序与索引自动排序的列的顺序的不对应度被称为聚合因子,聚合因子越大索引回表读越浪费时间(索引回表读不可避免的情况下)

Oracle执行计划分类:
1、TABLE ACCESS FULL  全表扫描
2、INDEX FAST FULL SCAN  索引快速扫描  (不考虑排序COUNT(ID), SUM(ID), AVG(ID),列必须非空或IS NOT NULL)
3、INDEX FULL SCAN  索引全扫  (SELECT ID FROM T WHERE ID = 120)
4、INDEX FULL SCAN(MIN/MAX)  最大值最小值索引全扫  (SELECT MAX(ID) FROM T)
5、TABLE ACCESS BY INDEX ROWID  索引回表读  (SELECT * FROM T WHERE ID = 1)
6、INDEX RANGE SCAN  索引范围扫描  (SELECT * FROM T WHERE ID < 100)
7、BITMAP INDEX FAST FULL SCAN  位图索引快速扫描  (不考虑排序COUNT(ID), SUM(ID), AVG(ID),位图快速索引扫描速度非常快将近是普通索引的百倍.列不必非空)

btree索引优化简介
T表  字段:OBJECT_ID, OBJECT_NAME
单列索引:
CREATE INDEX IDX1_OBJECT_ID ON T(OBJECT_ID);
COUNT(*)、SUM、AVG优化:
改为COUNT(OBJECT_ID)查询,但是必须保证OBJECT_ID列非空。

可用如下方法告知oracle可走IDX1_OBJECT_ID索引:
1、SELECT COUNT(OBJECT_ID) FROM T WHERE OBJECT_ID IS NOT NULL;
2、设置字段非空
MAX/MIN优化:
根据第三个特性有序排列,所以MAX/MIN的查询代价会非常小。
SELECT MAX(OBJECT_ID) FROM T; 不需加上IS NOT NULL; 使用执行计划:INDEX FULL SCAN(MIN/MAX);
ORDER BY、DISTINCT排序优化:
SELECT * FROM T WHERE OBJECT_ID < 100 ORDER BY OBJECT_ID;
未建立索引的情况下会进行排序产生TEMPSPC;
建立索引的情况下不需要产生排序 会使用IDX1_OBJECT_ID索引

位图索引
创建语法:
CREATE BITMAP INDEX IDX_BITM_T_STATUS ON T(STATUS);
适用在更新非常少的表,建立在重复度较高的列(性别)
存储结构:
位图索引存储的是比特位值

函数索引:
CREATE TABLE T AS SELECT * FROM DBA_OBJECT;
CREATE INDEX IDX_OBJECT_ID ON T(OBJECT_ID);
CREATE INDEX IDX_OBJECT_NAME ON T(OBJECT_NAME);
CREATE INDEX IDX_CREATED ON T(CREATED);
SELECT * FROM T WHERE UPPER(OBJECT_NAME) = 'T';

普通的BTREE索引,如果在对列做运算的条件下是无法使用索引查询的,会使用TABLE ACCESS FULL;
创建语句:
CREATE INDEX IDX_UPPER_OBJ_NAME ON(UPPER(OBJECT_NAME));
SELECT INDEX_NAME, INDEX_TYPE FROM USER_INDEXES WHERE TABLE_NAME = 'T';
函数索引的TYPE是:FUNCTION-BASED NORMAL;
函数索引的cost比全表扫描要小,但是比普通的索引要大的多。
SELECT * FROM T WHERE OBJECT_ID - 10<30;

这时候如果在object_id列建立普通索引时无法使用的。oracle会默认使用全表扫描的方式进行查询。可有以下两个思路进行优化:
1、SELECT * FROM T WHERE OBEJCT_ID < 40;
2、在OBJECT_ID - 10上建立函数索引
写sql时要注意规范,很多语句是等价的。
SELECT * FROM T WHERE SUBSTR(OBJECT_NAME,1,4) = 'CLUS'  =    SELECT * FROM T WHERE OBJECT_NAME LIKE 'CLUS%';
SELECT * FROM T WHERE TRUNC(CREATED) >= TO_DATE('2012-10-02', 'YYYY-MM-DD') AND TRUNC(CREATED) <= TO_DATE('2012-10-03','YYYY-MM-DD')
=
SELECT * FROM T WHERE CREATED >= TO_DATE('2012-10-02', 'YYYY-MM-DD') AND CREATED < TO_DATE('2012-10-03','YYYY-MM-DD')+1;
 
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 <> '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  特点 :
适合与大量的增、删、改(OLTP )
不能用包含OR 操作符的查询;
适合高基数的列(唯一值多)
典型的树状结构;
每个结点都是数据块;
大多都是物理上一层、两层或三层不定,逻辑上三层;
叶子块数据是排序的,从左向右递增;
在分支块和根块中放的是索引的范围;
 

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

Bitmap t 特点 :
适合与决策支持系统;
做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 语句的性能也同样得以提高, 这是因为行在物理上有序。由于键列的值在表和索引中都没有重复, 存储所需要的空间也随之减少。
如果不会频繁地根据主键列查询数据,则需要在索引组织表中的其他列上创建二级索引。不会频繁根据主键查询表的应用程序不会了解到使用索引组织表的全部优点。 对于总是通过对主键的精确匹配或范围扫描进行访问的表,就需要考虑使用索引组织表。

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

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 还支持并行查询和并行 DML 。这样就可以同时执行多个进程,从而加快处理这条语句。
2.7. 1.本地分区索引 ( 通常使用的索引 )
可以使用与表相同的分区键和范围界限来对本地索引分区。每个本地索引的分区只包含了它所关联的表分区的键和ROWID 。本地索引可以是 B 树或位图索引。如果是 B 树索引,它可以是唯一或不唯一的索引。
这种类型的索引支持分区独立性,这就意味着对于单独的分区,可以进行增加、截取、删除、分割、脱机等处理,而不用同时删除或重建索引。 Oracle自动维护这些本地索引。 本地索引分区还可以被单独重建,而其他分区不会受到影响。

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

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

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

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

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

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

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


          分区的、全局有前缀索引

技巧 : 如果一个全局索引将被对等分区,就必须把它创建为一个本地索引,这样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 索引的分类,分析与比较

逻辑上:
Single column 单行索引
Concatenated 多行索引
Unique 唯一索引
NonUnique 非唯一索引
Function-based函数索引
Domain 域索引

物理上:
Partitioned 分区索引
NonPartitioned 非分区索引
B-tree:
Normal 正常型B树
Rever Key 反转型B树
Bitmap 位图索引

索引结构:
B-tree:
适合与大量的增、删、改(OLTP);
不能用包含OR操作符的查询;
适合高基数的列(唯一值多)
典型的树状结构;
每个结点都是数据块;
大多都是物理上一层、两层或三层不定,逻辑上三层;
叶子块数据是排序的,从左向右递增;
在分支块和根块中放的是索引的范围;
Bitmap:
适合与决策支持系统;
做UPDATE代价非常高;
非常适合OR操作符的查询;
基数比较少的时候才能建位图索引;

树型结构:
索引头
开始ROWID,结束ROWID(先列出索引的最大范围)
BITMAP
每一个BIT对应着一个ROWID,它的值是1还是0,如果是1,表示着BIT对应的ROWID有值;[@more@]

Oracle索引分析与比较
首先给出各种索引的简要解释:
b*tree index:几乎所有的关系型数据库中都有b*tree类型索引,也是被最多使用的。其树结构与二叉树比较类似,根据rid快速定位所访问的行。

反向索引:反转了b*tree索引码中的字节,是索引条目分配更均匀,多用于并行服务器环境下,用于减少索引叶的竞争。

降序索引:8i中新出现的索引类型,针对逆向排序的查询。

位图索引:使用位图来管理与数据行的对应关系,多用于OLAP系统。

函数索引:这种索引中保存了数据列基于function返回的值,在select * from table where function(column)=value这种类型的语句中起作用。

2 各种索引的结构分析

2.1 B*Tree索引B*Tree索引是最常见的索引结构,默认建立的索引就是这种类型的索引。B*Tree索引在检索高基数数据列(高基数数据列是指该列有很多不同的值)时提供了最好的性能。当取出的行数占总行数比例较小时B-Tree索引比全表检索提供了更有效的方法。但当检查的范围超过表的10%时就不能提高取回数据的性能。B-Tree索引是基于二叉树的,由分支块(branch block)和叶块(leaf block)组成。在树结构中,位于最底层底块被称为叶块,包含每个被索引列的值和行所对应的rowid。在叶节点的上面是分支块,用来导航结构,包含了索引列(关键字)范围和另一索引块的地址。

假设我们要找索引中值为80的行,从索引树的最上层入口开始,定位到大于等于50,然后往左找,找到第2个分支块,定位为75-100,最后再定位到叶块上,找到80所对应的rowid,然后根据rowid去读取数据块获取数据。如果查询条件是范围选择的,比如where column >20 and column <80,那么会先定位到第一个包含20的叶块,然后横向查找其他的叶块,直到找到包含80的块为止,不用每次都从入口进去再重新定位。

2.2 反向索引
反向索引是B*Tree索引的一个分支,它的设计是为了运用在某些特定的环境下的。Oracle推出它的主要目的就是为了降低在并行服务器(Oracle Parallel Server)环境下索引叶块的争用。当B*Tree索引中有一列是由递增的序列号产生的话,那么这些索引信息基本上分布在同一个叶块,当用户修改或访问相似的列时,索引块很容易产生争用。反向索引中的索引码将会被分布到各个索引块中,减少了争用。反向索引反转了索引码中每列的字节,通过dump()函数我们可以清楚得看见它做了什么。举个例子:1,2,3三个连续的数,用dump()函数看它们在Oracle内部的表示方法。
    SQL> select 'number',dump(1,16) from dual
    2 union all select 'number',dump(2,16) from dual
    3 union all select 'number',dump(3,16) from dual;

    'NUMBE DUMP(1,16)
    ------ -----------------
    number Typ=2 Len=2: c1,2 (1)
    number Typ=2 Len=2: c1,3 (2)
    number Typ=2 Len=2: c1,4 (3)
    再对比一下反向以后的情况:
    SQL> select 'number',dump(reverse(1),16) from dual
    2 union all select 'number',dump(reverse(2),16) from dual
    3 union all select 'number',dump(reverse(3),16) from dual;

    'NUMBE DUMP(REVERSE(1),1
    ------ -----------------
    number Typ=2 Len=2: 2,c1 (1)
    number Typ=2 Len=2: 3,c1 (2)
    number Typ=2 Len=2: 4,c1 (3)

我们发现索引码的结构整个颠倒过来了,这样1,2,3个索引码基本上不会出现在同一个叶块里,所以减少了争用。不过反向索引又一个缺点就是不能在所有使用常规索引的地方使用。在范围搜索中其不能被使用,例如,where column>value,因为在索引的叶块中索引码没有分类,所以不能通过搜索相邻叶块完成区域扫描。

2.3 降序索引
降序索引是8i里面新出现的一种索引,是B*Tree的另一个衍生物,它的变化就是列在索引中的储存方式从升序变成了降序,在某些场合下降序索引将会起作用。举个例子,我们来查询一张表并进行排序:
SQL> select * from test where a between 1 and 100 order by a desc,b asc;
    已选择100行。
    Execution Plan
    ----------------------------------------------------------
    0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=100 Bytes=400)
    1 0 SORT(ORDER BY)(Cost=2 Card=100 Bytes=400)
    2 1 INDEX (RANGE SCAN) OF 'IND_BT' (NON-UNIQUE) (Cost=2 Card=100 Bytes=400)

这里优化器首先选择了一个索引范围扫描,然后还有一个排序的步骤。如果使用了降序索引,排序的过程会被取消。
   SQL> create index test.ind_desc on test.testrev(a desc,b asc);
    索引已创建。
    SQL> analyze index test.ind_desc compute statistics;
    索引已分析

再来看下执行路径:
    SQL> select * from test where a between 1 and 100 order by a desc,b asc;
    已选择100行。
    Execution Plan(SQL执行计划,稍后会讲解如何使用)。
    ----------------------------------------------------------
    0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=100 Bytes=400)
    1 0 INDEX (RANGE SCAN) OF 'IND_DESC' (NON-UNIQUE) (Cost=2 Card=100 Bytes=400)

我们看到排序过程消失了,这是因为创建降序索引时Oracle已经把数据都按降序排好了。另外一个需要注意的地方是要设置init.ora里面的compatible参数为8.1.0或以上,否则创建时desc关键字将被忽略。

2.4 位图索引
位图索引主要用于决策支持系统或静态数据,不支持行级锁定。位图索引最好用于低cardinality列(即列的唯一值除以行数为一个很小的值,接近零),例如又一个“性别”列,列值有“Male”,“Female”,“Null”等3种,但一共有300万条记录,那么3/3000000约等于0,这种情况下最适合用位图索引。
位图索引可以是简单的(单列)也可以是连接的(多列),但在实践中绝大多数是简单的。在这些列上多位图索引可以与AND或OR操作符结合使用。位图索引使用位图作为键值,对于表中的每一数据行位图包含了TRUE(1)、FALSE(0)、或NULL值。位图索引的位图存放在B-Tree结构的页节点中。B-Tree结构使查找位图非常方便和快速。另外,位图以一种压缩格式存放,因此占用的磁盘空间比B-Tree索引要小得多。
如果搜索where gender=’Male’,要统计性别是”Male”的列行数的话,Oracle很快就能从位图中找到共3行即第1,9,10行是符合条件的;如果要搜索where gender=’Male’ or gender=’Female’的列的行数的话,也很容易从位图中找到共8行即1,2,3,4,7,8,9,10行是符合条件的。如果要搜索表的值的话,那么Oracle会用内部的转换函数将位图中的相关信息转换成rowid来访问数据块。

2.5 函数索引
基于函数的索引也是8i以来的新产物,它有索引计算列的能力,它易于使用并且提供计算好的值,在不修改应用程序的逻辑上提高了查询性能。使用基于函数的索引有几个先决条件:
(1)必须拥有QUERY REWRITE(本模式下)或GLOBAL QUERY REWRITE(其他模式下)权限。
(2)必须使用基于成本的优化器,基于规则的优化器将被忽略。
(3)必须设置以下两个系统参数:
QUERY_REWRITE_ENABLED=TRUE
QUERY_REWRITE_INTEGRITY=TRUSTED
可以通过alter system set,alter session set在系统级或线程级设置,也可以通过在init.ora添加实现。这里举一个基于函数的索引的例子:
   SQL> create index test.ind_fun on test.testindex(upper(a));
    索引已创建。
    SQL> insert into testindex values('a',2);
    已创建 1 行。
    SQL> commit;
    提交完成。
    SQL> select /*+ RULE*/* FROM test.testindex where upper(a)='A';
    A B
    -- ----------
    a 2
    Execution Plan
    ----------------------------------------------------------
    0 SELECT STATEMENT Optimizer=HINT: RULE
    1 0 TABLE ACCESS (FULL) OF 'TESTINDEX'
    (优化器选择了全表扫描)
    --------------------------------------------------------------------
    SQL> select * FROM test.testindex where upper(a)='A';
    A B
    -- ----------
    a 2
    Execution Plan
    ----------------------------------------------------------
    0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=1 Bytes=5)
    1 0 TABLE ACCESS (BY INDEX ROWID) OF 'TESTINDEX' (Cost=2 Card=
    1 Bytes=5)
    2 1 INDEX (RANGE SCAN) OF 'IND_FUN' (NON-UNIQUE) (Cost=1 Car
    d=1)(使用了ind_fun索引)

3 各种索引的创建方法
(1)*Tree索引。
Create index indexname on tablename(columnname[columnname...])
(2)反向索引。
Create index indexname on tablename(columnname[columnname...]) reverse
(3)降序索引。
Create index indexname on tablename(columnname DESC[columnname...])
(4)位图索引。
Create BITMAP index indexname on tablename(columnname[columnname...])
(5)函数索引。
Create index indexname on tablename(functionname(columnname))
注意:创建索引后分析要索引才能起作用。
analyze index indexname compute statistics;
4 各种索引使用场合及建议(1)B*Tree索引。
常规索引,多用于oltp系统,快速定位行,应建立于高cardinality列(即列的唯一值除以行数为一个很大的值,存在很少的相同值)。

(2)反向索引。
B*Tree的衍生产物,应用于特殊场合,在ops环境加序列增加的列上建立,不适合做区域扫描。

(3)降序索引。
B*Tree的衍生产物,应用于有降序排列的搜索语句中,索引中储存了降序排列的索引码,提供了快速的降序搜索。

(4)位图索引。
位图方式管理的索引,适用于OLAP(在线分析)和DSS(决策处理)系统,应建立于低cardinality列,适合集中读取,不适合插入和修改,提供比B*Tree索引更节省的空间。

(5)函数索引。
B*Tree的衍生产物,应用于查询语句条件列上包含函数的情况,索引中储存了经过函数计算的索引码值。可以在不修改应用程序的基础上能提高查询效率。

5 附表(索引什么时候不工作)
首先要声明两个知识点:
(1)RBO&CBO。
Oracle有两种执行优化器,一种是RBO(Rule Based Optimizer)基于规则的优化器,这种优化器是基于sql语句写法选择执行路径的;另一种是CBO(Cost Based Optimizer)基于规则的优化器,这种优化器是Oracle根据统计分析信息来选择执行路径,如果表和索引没有进行分析,Oracle将会使用RBO代替CBO;如果表和索引很久未分析,CBO也有可能选择错误执行路径,不过CBO是Oracle发展的方向,自8i版本来已经逐渐取代RBO.
(2)AUTOTRACE。
要看索引是否被使用我们要借助Oracle的一个叫做AUTOTRACE功能,它显示了sql语句的执行路径,我们能看到Oracle内部是怎么执行sql的,这是一个非常好的辅助工具,在sql调优里广泛被运用。我们来看一下怎么运用AUTOTRACE:
① 由于AUTOTRACE自动为用户指定了Execution Plan,因此该用户使用AUTOTRACE前必须已经建立了PLAN_TABLE。如果没有的话,请运行utlxplan.sql脚本(它在$ORACLE_HOME/rdbms/admin目录中)。
② AUTOTRACE可以通过运行plustrce.sql脚本(它在$ORACLE_HOME/sqlplus/admin目录中)来设置,用sys用户登陆然后运行plustrce.sql后会建立一个PLUSTRACE角色,然后给相关用户授予PLUSTRACE角色,然后这些用户就可以使用AUTOTRACE功能了。
③ AUTOTRACE的默认使用方法是set autotrace on,但是这方法不总是适合各种场合,特别当返回行数很多的时候。Set autotrace traceonly提供了只查看统计信息而不查询数据的功能。
    SQL> set autotrace on
    SQL> select * from test;
    A
    ----------
    1
    Execution Plan
    ----------------------------------------------------------
    0 SELECT STATEMENT Optimizer=CHOOSE
    1 0 TABLE ACCESS (FULL) OF 'TEST'
    Statistics
    ----------------------------------------------------------
    0 recursive calls
    0 db block gets
    0 consistent gets
    0 physical reads
    0 redo size
    0 bytes sent via SQL*Net to client
    0 bytes received via SQL*Net from client
    0 SQL*Net roundtrips to/from client
    0 sorts (memory)
    0 sorts (disk)
    rows processed

    SQL> set autotrace traceonly
    SQL> select * from test.test;

    Execution Plan
    ----------------------------------------------------------
    0 SELECT STATEMENT Optimizer=CHOOSE
    1 0 TABLE ACCESS (FULL) OF 'TEST'

    Statistics
    ----------------------------------------------------------
    0 recursive calls
    0 db block gets
    0 consistent gets
    0 physical reads
    0 redo size
    0 bytes sent via SQL*Net to client
    0 bytes received via SQL*Net from client
    0 SQL*Net roundtrips to/from client
    0 sorts (memory)
    0 sorts (disk)
    rows processed

Hints是Oracle提供的一个辅助用法,按字面理解就是‘提示’的意思,确实它起得作用也是提示优化器按它所提供的关键字来选择执行路径,特别适用于sql调整的时候。使用方法如下:
{DELETE|INSERT|SELECT|UPDATE} /*+ hint [text] [hint[text]]... */
具体可参考Oracle SQL Reference。有了前面这些知识点,接下来让我们来看一下什么时候索引是不起作用的。以下列出几种情况。


索引常见操作                                                            改变索引:
SQL> alter index employees_last _name_idx storage(next 400K maxextents 100);
索引创建后,感觉不合理,也可以对其参数进行修改。详情查看相关文档

 

调整索引的空间:
新增加空间
SQL> alter index orders_region_id_idx allocate extent (size 200K datafile '/disk6/index01.dbf');

释放空间
SQL> alter index oraers_id_idx deallocate unused;

索引在使用的过程中可能会出现空间不足或空间浪费的情况,这个时候需要新增或释放空间。上面两条命令完成新增与释放操作。关于空间的新增oracle可以自动帮助,如果了解数据库的情况下手动增加可以提高性能。

 

重新创建索引:
所引是由oracle自动完成,当我们对数据库频繁的操作时,索引也会跟着进行修改,当我们在数据库中删除一条记录时,对应的索引中并没有把相应的索引只是做一个删除标记,但它依然占据着空间。除非一个块中所有的标记全被删除的时,整个块的空间才会被释放。这样时间久了,索引的性能就会下降。这个时候可以重新建立一个干净的索引来提高效率。
SQL> alter index orders_region_id_idx rebuild tablespace index02;

通过上面的命令就可以重现建立一个索引,oracle重建立索引的过程:
1、锁表,锁表之后其他人就不能对表做任何操作。
2、创建新的(干净的)临时索引。
3、把老的索引删除掉
4、把新的索引重新命名为老索引的名字
5、对表进行解锁。

 移动所引:
其实,我们移动索引到其它表空间也同样使用上面的命令,在指定表空间时指定不同的表空间。新的索引创建在别位置,把老的干掉,就相当于移动了。

SQL> alter index orders_region_id_idx rebuild tablespace index03;
 

在线重新创建索引:
上面介绍,在创建索引的时候,表是被锁定,不能被使用。对于一个大表,重新创建索引所需要的时间较长,为了满足用户对表操作的需求,就产生的这种在线重新创建索引。
SQL> alter index orders_id_idx  rebuild  online;

创建过程:
1、锁住表
2、创建立临时的和空的索引和IOT表用来存在on-going DML。普通表存放的键值,IOT所引表直接存放的表中数据;on-gong DML也就是用户所做的一些增删改的操作。
3、对表进行解锁
4、从老的索引创建一个新的索引。
5、IOT表里存放的是on-going DML信息,IOT表的内容与新创建的索引合并。
6、锁住表
7、再次将IOT表的内容更新到新索引中,把老的索引干掉。
8、把新的索引重新命名为老索引的名字
9、对表进行解锁

 整合索引碎片:
如上图,在很多索引中有剩余的空间,可以通过一个命令把剩余空间整合到一起。  
SQL> alter index orders_id_idx  coalesce;
 
删除索引:
SQL> drop  index  hr.departments_name_idx;

分析索引                                                                     检查所引的有效果,前面介绍,索引用的时间久了会产生大量的碎片、垃圾信息与浪费的剩余空间了。可以通过重新创建索引来提高所引的性能。
可以通过一条命令来完成分析索引,分析的结果会存放在在index_stats表中。
查看存放分析数据的表:
SQL> select count(*) from index_stats;

  COUNT(*)
----------
         0
执行分析索引命令:
SQL> analyze index my_bit_idx validate structure;

Index analyzed.

再次查看 index_stats 已经有了一条数据
SQL> select count(*) from index_stats;

  COUNT(*)
----------
         1

把数据查询出来:
SQL> select height,name,lf_rows,lf_blks,del_lf_rows from index_stats;

    HEIGHT   NAME              LF_ROWS   LF_BLKS   DEL_LF_ROWS
---------- ---------------------------------------------------------------------- ---------- -----------
         2   MY_BIT_IDX            1000          3            100 

分析数据分析:

(HEIGHT)这个所引高度是2 ,(NAME)索引名为MY_BIT_IDX  ,(LF_ROWS)所引表有1000行数据,(LF_BLKS)占用3个块,(DEL_LF_ROWS)删除100条记录。

  这里也验证了前面所说的一个问题,删除的100条数据只是标记为删除,因为总的数据条数依然为1000条,占用3个块,那么每个块大于333条记录,只有删除的数据大于333条记录,这时一个块被清空,总的数据条数才会减少。



索引
索引是关系数据库中用于存放每一条记录的一种对象,主要目的是加快数据的读取速度和完整性检查。建立索引是一项技术性要求高的工作。一般在数据库设计阶段的与数据库结构一道考虑。应用系统的性能直接与索引的合理直接有关。下面给出建立索引的方法和要点。
§3.5.1 建立索引
1. CREATE INDEX命令语法:
CREATE INDEX
CREATE [unique] INDEX [user.]index
ON [user.]table (column [ASC | DESC] [,column
[ASC | DESC] ] ... )
[CLUSTER [scheam.]cluster]
[INITRANS n]
[MAXTRANS n]
[PCTFREE n]
[STORAGE storage]
[TABLESPACE tablespace]
[NO SORT]
Advanced
其中:
   schema ORACLE模式,缺省即为当前帐户
   index 索引名
   table 创建索引的基表名
   column 基表中的列名,一个索引最多有16列,long列、long raw
              列不能建索引列
   DESC、ASC 缺省为ASC即升序排序
   CLUSTER 指定一个聚簇(Hash cluster不能建索引)
   INITRANS、MAXTRANS 指定初始和最大事务入口数
   Tablespace 表空间名
   STORAGE 存储参数,同create table 中的storage.
   PCTFREE 索引数据块空闲空间的百分比(不能指定pctused)
   NOSORT 不(能)排序(存储时就已按升序,所以指出不再排序)
2.建立索引的目的:
建立索引的目的是:
l 提高对表的查询速度;
l 对表有关列的取值进行检查。
但是,对表进行insert,update,delete处理时,由于要表的存放位置记录到索引项中而会降低一些速度。
注意:一个基表不能建太多的索引;
      空值不能被索引
      只有唯一索引才真正提高速度,一般的索引只能提高30%左右。
   Create index ename_in on emp (ename,sal);
例1:商场的商品库表结构如下,我们为该表的商品代码建立一唯一索引,使得在前台POS收款时提高查询速度。
Create table good(good_id number(8) not null,/* 商品条码 */
                   Good_desc varchar2(40), /* 商品描述 */
                   Unit_cost number(10,2) /* 单价 */
                   Good_unit varchar2(6), /* 单位 */
                   Unit_pric number(10,2) /* 零售价 */
                   );
注:提高查询速度的方法还有在表上建立主键,主键与唯一索引的差别
在于唯一索引可以空,主键为非空,比如:
Create table good(good_id number(8) primary key,
                    Good_desc Varchar2(40),
                    Unit_cost number(10,2),
                    Good_unit char(6),
                    Unit_pric number(10,2)
                   );
§3.5.2 修改索引
对于较早的Oracle版本,修改索引的主要任务是修改已存在索引的存储参数适应增长的需要或者重新建立索引。而Oracle8I及以后的版本,可以对无用的空间进行合并。这些的工作主要是由管理员来完成。
简要语法结构如下,更详细的语法图见电子文档《Oracle8i Reference 》 中的 Alter index.
ALTER [UNIQUE] INDEX [user.]index
[INITRANS n]
[MAXTRANS n] 
REBUILD 
[STORAGE n]
其中:
REBUILD 是 根据原来的索引结构重新建立索引,实际是删除原来的索引后再重新建立。
提示:DBA经常用 REBUILD 来重建索引可以减少硬盘碎片和提高应用系统的性能。
例:
alter index pk_detno rebuild storage(initial 1m next 512k);
ALTER INDEX emp_ix REBUILD REVERSE;
Oracle8i 的新功能可以对索引的无用空间进行合并,它由下面命令完成:
ALTER INDEX . . . COALESCE;
例如:
ALTER INDEX ename_idx COALESCE;
§3.5.3 删除索引
当不需要时可以将索引删除以释放出硬盘空间。命令如下:
DROP INDEX [schema.]indexname
例如:
sql> drop index pk_dept;
注:当表结构被删除时,有其相关的所有索引也随之被删除。
§3.6 新索引类型
Oracle8i为了性能优化而提供新的创建新类型的索引。这些新索引在下面介绍:
§3.6.1 基于函数的索引
基于函数的索引就是存储预先计算好的函数或表达式值的索引。这些表达式可以是算术运算表达式、SQL或PL/SQL函数、C调用等。值得注意的是,一般用户要创建函数索引,必须具有GLOBAL QUERY REWRITE和CREATE ANY INDEX权限。否则不能创建函数索引,看下面例子:
例1:为EMP表的ename 列建立大写转换函数的索引idx :
CREATE INDEX idx ON emp ( UPPER(ename));
这样就可以在查询语句来使用:
SELECT * FROM EMP WHERE UPPER(ename) LIKE ‘JOH%’;
例2:为emp 的工资和奖金之和建立索引:
1) 查看emp 的表结构:
SQL> desc emp
 Name Null? Type
 ----------------------------------------- -------- ------------------
 EMPNO NOT NULL NUMBER(4)
 ENAME VARCHAR2(10)
 JOB VARCHAR2(9)
 MGR NUMBER(4)
 HIREDATE DATE
 SAL NUMBER(7,2)
 COMM NUMBER(7,2)
 DEPTNO NUMBER(2)
2)没有授权就创建函数索引的提示:
SQL> create index sal_comm on emp ( (sal+comm)*12, sal,comm)
 2 tablespace users storage(initial 64k next 64k pctincrease 0);
create index sal_comm on emp ( (sal+comm)*12, sal,comm)
                                          *
ERROR at line 1:
ORA-01031: insufficient privileges
3) 连接到DBA帐户并授权:
SQL> connect sys/sys@ora816
Connected.
SQL> grant GLOBAL QUERY REWRITE to scott;
Grant succeeded.
SQL> grant CREATE ANY INDEX to scott;
Grant succeeded.
4)在连接到scott帐户,创建基于函数的索引:
SQL> connect scott/tiger@ora816
Connected.
SQL> create index sal_comm on emp ( (sal+comm)*12, sal,comm)
 2 tablespace users storage(initial 64k next 64k pctincrease 0);
Index created.
1)在查询中使用函数索引:
SQL> select ename,sal,comm from emp where (sal+comm)*12 >5000;
ENAME SAL COMM
---------------------- ---------------- ----------------
ALLEN 1600 300
WARD 1250 500
MARTIN 1250 1400
TURNER 1500 0
    赵元杰 1234.5 54321
§3.6.2 反向键索引
反向键索引通过反向键保持索引的所有叶子键上的插入分布。有时,可用反向键索引来避免不平衡的索引。对于反向键索引可以进行下面操作:
l 通过在ALTER INDEX命令后加REBUILD NOREVERSE或REBUILD REVERSE子句来使索引边为反向键索引或普通索引;
l 采用范围扫描的查询不能使用反向键索引;
l 位图索引不能反向;
l 索引编排表不能反向。
例1:创建一个反向键索引:
CREATE INDEX i ON t (a,b,c) REVERSE;
例2:使一个索引变为反向键索引:
ALTER INDEX i REBUILD NOREVERSE;
§3.6.3 索引组织表
与普通的索引不一样,索引组织表(Index_Organized Table)是根据表来存储数据,即将索引和表存储在一起。这样的索引结构表(Index_organized table—IOT)的特点是:对表数据的改变,如插入一新行、删除某行都引起索引的更新。
索引组织表就象带一个或多个列所有的普通表一样,但索引组织表在B-树索引结构的叶节点上存储行数据。通过在索引结构中存储数据,索引组织表减少了总的存储量,此外,索引组织表也改善访问性能。
由于表中的行与B_树索引存放在一起,每个行都没有ROWID,而是用主键来标识。但是Oracle会“猜”这些行的位置并为每个行分配逻辑的ROWID。此外,你可以为这样的表建立第二个索引。
创建索引结构表也是用CREATE TABLE 命令加ORGANIZATION INDEX关键字来实现。但是,这样的表在创建完后,你还必须为该表建立一个主键。
例子:
CREATE TABLE IOT_EXPAMPLE
(
Pk_col1 number(4),
Pk_col2 varchar2(10),
Non_pk_col1 varchar2(40),
Non_pk_col2 date,
CONSTRAINT pk_iot PRIMARY KEY
                 ( pk_col1, pk_col2)
)
ORGANIZATION INDEX
TABLESPACE INDEX
STORAGE( INITIAL 1M NEXT 512K PCTINCREASE 0 );
索引组织表有些限制:
l 不能使用唯一约束;
l 必须具有一个主键;
l 不能建立簇;
l 不能包含LONG类型列;
l 不支持分布和复制。
提示:如果建立了索引组织表,则会在DBA_TABLES中的IOT_TYPE和IOT_NAME列上记录有索引组织表的信息。
例1.修改索引结构表 docindex 的索引段的INITRANS参数:
ALTER TABLE docindex INITRANS 4;
例2.下面语句加一个的溢出数据段到索引组织表 docindex中:
ALTER TABLE docindex ADD OVERFLOW;
例3.下面语句为索引组织表 docindex的溢出数据段修改INITRANS参数:
ALTER TABLE docindex OVERFLOW INITRANS 4;
============================================================================================================
适当的使用索引可以提高数据检索速度,可以给经常需要进行查询的字段创建索引
oracle的索引分为5种:唯一索引,组合索引,反向键索引,位图索引,基于函数的索引
创建索引的标准语法:
CREATE INDEX 索引名 ON 表名 (列名) 
     TABLESPACE 表空间名; 
创建唯一索引:
CREATE unique INDEX 索引名 ON 表名 (列名) 
     TABLESPACE 表空间名; 
创建组合索引:
CREATE INDEX 索引名 ON 表名 (列名1,列名2) 
     TABLESPACE 表空间名; 
创建反向键索引:
CREATE INDEX 索引名 ON 表名 (列名) reverse
     TABLESPACE 表空间名; 
查看文章   
oracle 查看索引类别以及查看索引字段被引用的字段方法2008年01月04日 星期五 13:20查看索引个数和类别
select * from user_indexes where table='表名' ;
查看索引被索引的字段
SQL>select * from user_ind_columns where index_name=upper('&index_name');
PS:
查看某表的约束条件
SQL>select constraint_name, constraint_type,search_condition, r_constraint_name 
from user_constraints where table_name = upper('&table_name'); 
SQL>select c.constraint_name,c.constraint_type,cc.column_name 
from user_constraints c,user_cons_columns cc 
where c.owner = upper('&table_owner') and c.table_name = upper('&table_name') 
and c.owner = cc.owner and c.constraint_name = cc.constraint_name 
order by cc.position;
查看视图的名称
SQL>select view_name from user_views;


 
Oracle索引index创建删除 
 
在查中文字典的时候,我们之所以能够很快的查到所要查找的字是因为字典建立了索引。同样,为了高效的获取数据,在数据量比较大的时候,我们需要给表中的某一列建立索引。
建立索引的作用是明显的,主要有:
1、快速存取数据
2、改善数据库性能,保证列值的唯一性
3、在使用order 

按照存储方法可以将索引分为B*树索引和位图索引。
B*树索引:顾名思义其存储类型就是一棵树,有分支和叶,分支相当于书的大目录,叶则相当于具体的书页。Oracle用B*树机制存储索引条目,可以保证用最短路径访问键值。默认情况下大多使用B*树索引。
位图索引:位图索引存储主要用于节省空间,减少Oracle对数据块的访问,它采用位图偏移方式来与表的行id号对应,采用位图索引一般是重复值太多的表字段。位图索引在实际密集型OLTP(数据事务处理)中用得比较少,因为OLTP会对表进行大量的删除、修改、添加操作,Oracle每次进行这些操作的时候都会对要操作的数据块加锁,以防止多人操作容易产生的数据块锁等待甚至死锁现象。而在OLAP(数据分析处理)中应用位图有优势,因为OLAP中大部分是对数据库的查询操作,而且一般采用数据仓库技术,所以大量数据采用位图索引节省空间比较明显。 
 
建立索引:
语法格式:
 
Sql代码  
create [unique | bitmap] index [schema.]indexName   
on [schema.]tableName(columnName[ASC | DESC],...n)   
[tablespace tablespaceName] [nosort] [reverse]  
 
其中,unique指定索引所基于的列值必须唯一。默认的索引是非唯一索引。Oracle建议不要在表上显示的定义unique索引。BITMAP指定建立位图索引。 
删除索引:
 
Sql代码  
drop index indexName;

Oracle中的索引详解

本页包含5张图片,默认未加载,显示所有图片

crazy

一、 ROWID的概念

存储了row在数据文件中的具体位置:64位 编码的数据,A-Z, a-z, 0-9, +, 和 /,

row在数据块中的存储方式

SELECT ROWID, last_name FROM hr.employees WHERE department_id = 20;

比 如:OOOOOOFFFBBBBBBRRR

OOOOOO:data object number, 对应dba_objects.data_object_id

FFF:file#, 对应v$datafile.file#

BBBBBB:block#

RRR:row#

Dbms_rowid包

SELECT dbms_rowid.rowid_block_number('AAAGFqAABAAAIWEAAA') from dual;

具 体到特定的物理文件

二、 索引的概念

1、 类似书的目录结构

2、 Oracle 的“索引”对象,与表关联的可选对象,提高SQL查询语句的速度

3、 索引直接指向包含所查询值的行的位置,减少磁盘I/O

4、 与所索引的表是相互独立的物理结构

5、 Oracle 自动使用并维护索引,插入、删除、更新表后,自动更新索引

6、 语法:CREATE INDEX index ON table (column[, column]...);

7、 B-tree结构(非bitmap):

[一]了解索引的工作原理:

表:emp

点击加载图片
目标:查询Frank的工资salary

建立索 引:create index emp_name_idx on emp(name);

点击加载图片
 

点击加载图片

[试验]测试索引的作用:
1. 运行/rdbms/admin/utlxplan 脚本

2. 建立测试表

create table t as select * from dba_objects;

insert into t select * from t;

create table indextable

as select rownum id,owner,object_name,subobject_name,

object_id,data_object_id,object_type,created

from t;

3. set autotrace trace explain

4. set timing on

5. 分析表,可以得到cost

6. 查询 object_name=’DBA_INDEXES’

7. 在object_name列上建立索引

8. 再查询

[思考]索引的代价:

插入,更新

三、 唯一索引

1、 何时创建:当某列任意两行的值都不相同

2、 当建立Primary Key(主键)或者Unique constraint(唯一约束)时,唯一索引将被自动建立

3、 语法:CREATE UNIQUE INDEX index ON table (column);

4、 演示

四、 组合索引

1、 何时创建:当两个或多个列经常一起出现在where条件中时,则在这些列上同时创建组合索引

2、 组合索引中列的顺序是任意的,也无需相邻。但是建议将最频繁访问的列放在列表的最前面

3、 演示(组合列,单独列)

五、 位图索引

1、 何时创建:

列中有非常多的重复的值时候。例如某列保存了 “性别”信息。

Where 条件中包含了很多OR操作符。

较少的update操作,因为要相应的跟新所有的bitmap

2、 结构:位图索引使用位图作为键值,对于表中的每一数据行位图包含了TRUE(1)、FALSE(0)、或NULL值。

3、 优点:位图以一种压缩格式存放,因此占用的磁盘空间比标准索引要小得多

4、 语法:CREATE BITMAP INDEX index ON table (column[, column]...);

5、 掩饰:

create table bitmaptable as select * from indextable where owner in('SYS','PUBLIC');

分析,查找,建立索引,查找

六、 基于函数的索引

   1、 何时创建:在WHERE条件语句中包含函数或者表达式时

2、 函数包括:算数表达式、PL/SQL函数、程序包函数、SQL函数、用户自定义函数。

3、 语法:CREATE INDEX index ON table (FUNCTION(column));

4、 演示

必须要分析表,并且 query_rewrite_enabled=TRUE

或者使用提示/*+ INDEX(ic_index)*/

七、 反向键索引

目的:比如索引值是一个自动增长的列:

点击加载图片
多个用户对集中在少数块上的索引行进行修改,容易引起资源的争用,比如对数据块的等待。此时建立反向索 引。

性能问题:

语法:

重建为标准索引:反之不行

八、 键压缩索引

比如表landscp的数据如下:

site feature job

Britten Park, Rose Bed 1, Prune

Britten Park, Rose Bed 1, Mulch

Britten Park, Rose Bed 1,Spray

Britten Park, Shrub Bed 1, Mulch

Britten Park, Shrub Bed 1, Weed

Britten Park, Shrub Bed 1, Hoe

……

查询时,以上3列均在where条件中同时出现,所以建立基于以上3列的组合索引。但是发现重复值很多,所以考虑压缩特性。

Create index zip_idx

on landscp(site, feature, job)

compress 2;

将索引项分成前缀(prefix)和后缀(postfix)两部分。前两项被放置到前缀部分。

Prefix 0: Britten Park, Rose Bed 1

Prefix 1: Britten Park, Shrub Bed 1

实际所以的结构为:

0 Prune

0 Mulch

0 Spray

1 Mulch

1 Weed

1 Hoe

特点:组合索引的前缀部分具 有非选择性时,考虑使用压缩。减少I/O,增加性能。

九、 索引组织表(IOT)

将表中的数据按照索 引的结构存储在索引中,提高查询速度。

牺牲插入更新的性能,换取查询 性能。通常用于数据仓库,提供大量的查询,极少的插入修改工作。

必须指定主键。插入数据时,会根据主键列进行B树索引排序,写入磁盘。

十、 分区索引

簇:

A cluster is a group of tables that share the same data blocks because they share common columns and are often used together.

oracle中最常用的索引就两种:B树索引和位图索引,这里就来简单说下这两种索引的使用。
B-树索引在Oracle中是一个通用的索引,在创建索引时它就是默认的索引类型。最多可以包括32列。
位图索引Oracle为每个唯一键创建一个位图,然后把与键值所关联的ROWID保存为位图。最多可以包括30列。
一般情况下,大多数用户都只创建TYPE为NORMAL的B-树索引,所以对于较低基数的列我们都是不创建索引的,因为B-树索引对查询速度提升不一定会有改善,甚至会增加Insert、Update、Delete命令所消耗的时间。
位图索引在加载表(插入操作)时通常要比B-树索引做得好。通常,位图索引要比一个低基数(很少不同值)上的B-树索引要快3~4倍,但如果新增的值占插入行的70%以上时,B-树索引通常会更快一些。当每条记录都增加一个新值时,B-树索引要比位图索引快3倍。
建议不要在一些联机事务处理(OLTP)应用程序中使用位图索引。B-树索引的索引值中包含ROWID,这样Oracle就可以在行级别上锁定索引。位图索引被存储为压缩的索引值,其中包含了一个范围内的ROWID,因此ORACLE必须针对一个给定值锁定所有范围内的ROWID。这种锁定可能自阿某些DML语句中造成死锁。SELECT语句不会受到这种锁定问题的影响。
位图索引有很多限制:
1、 基于规则的优化器不会考虑位图索引
2、 当执行ATLER TABLE语句,并修改包含有位图索引的列时,会使位图索引实效
3、 位图索引在索引块中储存了索引键的值;然而,他们并不能用户任何类型的完整性检查
4、 位图索引不能被申明为唯一索引
以上是援引的一些简单概念,下面是我实际工作中总结出来的:
我要做一个查询,涉及两个表t_sym_dict,t_sym_operlog,表结构分别如下:
X
其中t_sym_operlog的索引如下:

上面基数比较小的三列创建了位图索引
t_sym_dict的索引如下:

查询语句如下:
select (select c.dict_name
from t_sym_dict c
where c.dict_typeid = 'SYM_CITYINFO'
and c.dict_id = t.memo) 分公司,
t.staff_id 工号
from t_sym_operlog t
where t.operlog_subtype = '103'
and t.obj_type = 'CUSTLINKINFO'
and t.memo = '200'
-- and t.extsys_code = ''
-- and t.staff_id = ''
and t.oper_date >= to_date('20110501000000', 'yyyymmddhh24miss')
and t.oper_date <= to_date('20110530000000', 'yyyymmddhh24miss')
-- order byt.memo, t.oper_date
然后就出现了如下奇怪的现象(索引的创建没有问题)
1、索引使用正常

2、下面的看不到oper_date索引的使用

3、下面的看不到t_sym_operlog表的索引使用

尝试的解决的办法:
对数据表做采集,就是analysis
BEGIN
DBMS_STATS.gather_table_stats(ownname => 'CSID',tabname => 't_sym_operlog_back');
end;
猜测的导致原因:
当你运用SQL语言,向数据库发布一条查询语句时,ORACLE将伴随产生一个“执行计划”,也就是该语句将通过何种数据搜索方案执行,是通过全表扫描、还是通过索引搜寻等其它方式。搜索方案的选用与ORACLE的优化器息息相关。
SQL语句的执行步骤
   一条SQL语句的处理过程要经过以下几个步骤。
1 语法分析 分析语句的语法是否符合规范,衡量语句中各表达式的意义。
2 语义分析 检查语句中涉及的所有数据库对象是否存在,且用户有相应的权限。
3 视图转换 将涉及视图的查询语句转换为相应的对基表查询语句。
4 表达式转换 将复杂的SQL表达式转换为较简单的等效连接表达式。
5 选择优化器 不同的优化器一般产生不同的“执行计划”
6 选择连接方式 ORACLE有三种连接方式,对多表连接ORACLE可选择适当的连接方式。
7 选择连接顺序 对多表连接ORACLE选择哪一对表先连接,选择这两表中哪个表做为源数据表。
8 选择数据的搜索路径 根据以上条件选择合适的数据搜索路径,如是选用全表搜索还是利用索引或是其他的方式。
9 运行“执行计划”
分析:
oracle优化器CBO存在的典型问题:
有时,表明明建有索引,但查询过程显然没有用到相关的索引,导致查询过程耗时漫长,占用资源巨大,问题到底出在哪儿呢?按照以下顺序查找,基本上能发现原因所在。
查找原因的步骤
  首先,我们要确定数据库运行在何种优化模式下,相应的参数是:optimizer_mode。可在svrmgrl中运行“show parameter optimizer_mode'来查看。ORACLE V7以来缺省的设置应是'choose',即如果对已分析的表查询的话选择CBO,否则选择RBO。如果该参数设为“rule”,则不论表是否分析过,一概选用RBO,除非在语句中用hint强制。
  其次,检查被索引的列或组合索引的首列是否出现在PL/SQL语句的WHERE子句中,这是“执行计划”能用到相关索引的必要条件。
  第三,看采用了哪种类型的连接方式。ORACLE的共有Sort Merge Join(SMJ)、Hash Join(HJ)和Nested Loop Join(NL)。在两张表连接,且内表的目标列上建有索引时,只有Nested Loop才能有效地利用到该索引。SMJ即使相关列上建有索引,最多只能因索引的存在,避免数据排序过程。HJ由于须做HASH运算,索引的存在对数据查询速度几乎没有影响。
  第四,看连接顺序是否允许使用相关索引。假设表emp的deptno列上有索引,表dept的列deptno上无索引,WHERE语句有emp.deptno=dept.deptno条件。在做NL连接时,emp做为外表,先被访问,由于连接机制原因,外表的数据访问方式是全表扫描,emp.deptno上的索引显然是用不上,最多在其上做索引全扫描或索引快速全扫描。
  第五,是否用到系统数据字典表或视图。由于系统数据字典表都未被分析过,可能导致极差的“执行计划”。但是不要擅自对数据字典表做分析,否则可能导致死锁,或系统性能下降。
  第六,索引列是否函数的参数。如是,索引在查询时用不上。
  第七,是否存在潜在的数据类型转换。如将字符型数据与数值型数据比较,ORACLE会自动将字符型用to_number()函数进行转换,从而导致第六种现象的发生。
  第八,是否为表和相关的索引搜集足够的统计数据。对数据经常有增、删、改的表最好定期对表和索引进行分析,可用SQL语句“analyze table xxxx compute statistics for all indexes;'。ORACLE掌握了充分反映实际的统计数据,才有可能做出正确的选择。
  第九,索引列的选择性不高。
  我们假设典型情况,有表emp,共有一百万行数据,但其中的emp.deptno列,数据只有4种不同的值,如10、20、30、40。虽然emp数据行有很多,ORACLE缺省认定表中列的值是在所有数据行均匀分布的,也就是说每种deptno值各有25万数据行与之对应。假设SQL搜索条件DEPTNO=10,利用deptno列上的索引进行数据搜索效率,往往不比全表扫描的高,ORACLE理所当然对索引“视而不见”,认为该索引的选择性不高。
  但我们考虑另一种情况,如果一百万数据行实际不是在4种deptno值间平均分配,其中有99万行对应着值10,5000行对应值20,3000行对应值30,2000行对应值40。在这种数据分布图案中对除值为10外的其它deptno值搜索时,毫无疑问,如果索引能被应用,那么效率会高出很多。我们可以采用对该索引列进行单独分析,或用analyze语句对该列建立直方图,对该列搜集足够的统计数据,使ORACLE在搜索选择性较高的值能用上索引。
  第十,索引列值是否可为空(NULL)。如果索引列值可以是空值,在SQL语句中那些需要返回NULL值的操作,将不会用到索引,如COUNT(*),而是用全表扫描。这是因为索引中存储值不能为全空。
  第十一,看是否有用到并行查询(PQO)。并行查询将不会用到索引。
  第十二,看PL/SQL语句中是否有用到bind变量。由于数据库不知道bind变量具体是什么值,在做非相等连接时,如“<”,“>”,“like”等。ORACLE将引用缺省值,在某些情况下会对执行计划造成影响。
  如果从以上几个方面都查不出原因的话,我们只好用采用在语句中加hint的方式强制ORACLE使用最优的“执行计划”。
  hint采用注释的方式,有行注释和段注释两种方式。
  如我们想要用到A表的IND_COL1索引的话,可采用以下方式:
  “SELECT * FROM A WHERE COL1 = XXX;'
  注意,注释符必须跟在SELECT之后,且注释中的“+”要紧跟着注释起始符“/*”或“--”,否则hint就被认为是一般注释,对PL/SQL语句的执行不产生任何影响。
两种有效的跟踪调试方法
  ORACLE提供了两种有效的工具来跟踪调试PL/SQL语句的执行计划。
  一种是EXPLAIN TABLE方式。用户必须首先在自己的模式(SCHEMA)下,建立PLAN_TABLE表,执行计划的每一步骤都将记录在该表中,建表SQL脚本为在${ORACLE_HOME}/rdbms/admin/下的utlxplan.sql。
  打开SQL*PLUS,输入“SET AUTOTRACE ON”,然后运行待调试的SQL语句。在给出查询结果后,ORACLE将显示相应的“执行计划”,包括优化器类型、执行代价、连接方式、连接顺序、数据搜索路径以及相应的连续读、物理读等资源代价。
  如果我们不能确定需要跟踪的具体SQL语句,比如某个应用使用一段时间后,响应速度忽然变慢。我们这时可以利用ORACLE提供的另一个有力工具TKPROF,对应用的执行过程全程跟踪。
  我们要先在系统视图V$SESSION中,可根据USERID或MACHINE,查出相应的SID和SERIAL#。
  以SYS或其他有执行DBMS_SYSTEM程序包的用户连接数据库,执行“EXECUTE DBMS_SYSTEM.SET_SQL_TRACE_IN_SESSION(SID,SERIAL#,TRUE);”。
  然后运行应用程序,这时在服务器端,数据库参数“USER_DUMP_DEST”指示的目录下,会生成ora__xxxx.trc文件,其中xxxx为被跟踪应用的操作系统进程号。
  应用程序执行完成后,用命令tkprof对该文件进行分析。命令示例:“tkprof tracefile outputfile explain=useri

猜你喜欢

转载自zhyp29.iteye.com/blog/2300367
今日推荐