ORACLE创建索引思路

何为索引

索引是一种数据结构,是为了更快速的访问到数据。
索引是各种关系数据库系统最常见的一种逻辑单元,是关系数据库系统举足轻重的重要组成部分,对于提高检索数据速度有着至关重要的作用,索引的原理是根据索引值得到行指针(ROWID),然后快速定位到数据库记录
就像一本字典的目录一样,我们去找一个字的时候也不可能从第一页找到最后一页,我们也是在目录中根据拼音或者部首去查询这个字所在的页数范围。索引就相当于书或者字典的目录。

常用索引介绍

1.B-Tree索引 这是最常见的索引,几乎所有的关系型数据库系统都支持B树结构的索引,也是被最多使用的,其树结构与二叉树比较类似,根据行id快速定位到行。大部分数据库默认建立的索引就是这种索引。B树索引在检索高基数数据列(高基数列是指该列有很多不同的值,该列所有不同值的个数之和与该列所有值的个数之和的比成为列基数)时提供了比较好的性能,B树索引是基于二叉树的,由分支块和叶块组成。在树结构中,位于最底层的块成为叶块,包含每个被索引列的值和行所对应的rowid。在叶节点的上面是分支块,用来导航结构,包含了索引列(关键字)范围和另一索引快的地址。

2.位图索引 它不是B树结构的索引,位图索引相对于B-tree索引来说,它的存储结构是不一样的,通常在B-tree索引中,索引条目和行之间有一对一的关系。对于位图索引,一个索引条目使用一个位图同时指向许多行。这对于基本上只读的低基数(数据只有很少的几个截然不同的值)数据是合适的。比如说,一个person表,有个性别字段sex,Y代表男,N代表女,对于有几百万行数据的表来说,位图索引是一个非常好的选择。它可以迅速的扫描出来,而不用象对B树索引那样的查找。

然而位图索引的特性也决定了它不能应用到OLTP系统中,因为当我们对sex=Y条件的某一条数据进行UPDATE时,他会锁定sex=Y的全部记录,位图索引主要用于OLAP系统中,所以这里说的主要是B-Tree索引

B-Tree索引结构图

时间戳字段加索引会失效吗_字段

B-Tree索引又可细分为:普通索引,反向键索引,降序索引

我们大多数创建的索引都是普通索引

  1. 普通索引
创建语法:
CREATE INDEX index_name ON TABLE_NAME(table_column) TABLESPACE index_tablespace;
例如:CREATE INDEX IDX_ORDER_TIME ON T_ORDER(CREATEDATETIME) TABLESPACE INDX_SPC;
  1. 反向键索引(又称反转索引)
创建语法:
CREATE INDEX ndex_name ON TABLE_NAME(table_column) REVERSE TABLESPACE index_tablespace;

反向键索引主要用于数字连续型字段,比如序列,序列产生的值是唯一且递增的。比如101,102,103三个值,常规存储方式会存到一个BLOCK,
通过反向键索引会变成101,201,301,这样就变成了不连续的三个值会存到三个BLOCK。

优点:可以有效的避免热点块的争用,在大量INSERT时可以避免单个block的争用,比如enq: TX - allocate ITL entry,enq: TX - index contention这些等待事件可以有效降低
缺点:因为键值不是有序排列,所以基于索引的范围扫描将会失效,比如between,> <等,在于其他表关联时的index range scan有可能会失效。

  1. 降序索引

普通索引默认是升序排列的,对于业务大多数需要降序排列的字段适合创建降序索引。

创建语法:
CREATE INDEX ndex_name ON TABLE_NAME(table_column desc )  TABLESPACE index_tablespace;

注意:
需要在谓词中加入索引字段才会使用降序索引,比如时间字段创建降序索引需写WHERE createtime=??? ORDER BY createtime desc
如果where条件后没有时间字段依然使用不到降序索引。

如何创建高效索引

规则1:索引一定要在建表的时候考虑创建(未雨绸缪,居安思危)
因为刚开始时数据量少,在低效的SQL也不会体现出问题的存在,在数据慢慢增长到一定规模时候,这个时候再去创建索引将会面临很多问题,比如创建索引花费的时间变长,创建索引会对表内数据加锁,即使加了ONLINE参数也不能解决这一问题,所以这里主要是对业务产生影响,数据无法进行DML操作,影响的时长就是创建索引的时长。

规则2:索引一定要建到有用的字段上(好钢用到刀刃上)
索引是一种用空间换时间的手段,索引和表一样,同样需要占用磁盘空间。

① 在WHERE条件后经常出现的字段上应尽量考虑创建索引,但这并不意味着所有的条件字段都应该建索引。
规范中写到了单表索引不得超过5个,因为SQL在解析时会选择使用哪个索引,索引越多,相应的选择时间就越长。
注意:索引和表一样,同样会占用物理空间,在表内数据变更时,索引同样也会变更,索引会导致表上的DML操作变慢。
② 时间字段上一定要创建索引,在代码中书写的SQL应尽量使用时间字段去过滤掉大部分数据。
③ 字段重复值非常少,比如ID,高度唯一,比如系统中的loginid,orderid这些字段上创建索引会非常高效,通常只需极少的读取即可取到数据。
④ 对于只存在0,1值的字段,如果0占用了其中百分之九十,1只占用了百分之10,业务中也只会去查询1值的情况,这种字段也适合创建索引
⑤ 外键字段上一定要创建索引,否则会出现严重的阻塞。
⑥ 在多表的关联字段上创建索引。
⑦ 创建复合索引
单个字段的选择性可能不高,但是组合查询时返回的数据量会特别少,这类型的查询考虑创建组合索引,创建组合索引时最前面的字段称为前导列,SQL中的谓词条件如果没有前导列,复合索引可能无法用到。而在查询中如果只写前导列是有可能会用到索引的。
所以,在创建复合索引时,具体哪个字段当做前导列要做斟酌
比如t_baseattribute表的OBJTYPE, OBJID, ATTRDICTIONARYID组合索引 --OBJTYPE就是前导列
t_card表的CARDBATCH, ACTIVATED, FROZEN, CANCELED, BOUND组合索引
t_pricerec表的DIRECTION, NEEDPAY, MONEYTYPEID, OBJTYPEID, PRICEUSAGETYPEID, OBJID组合索引

造成索引失效的原因
很多时候我们创建了索引,谓词条件也使用了索引,但是发现SQL依然是全表扫描,有以下几个因素会导致索引失效,在编写SQL时应避免

(1)索引列上的隐式转换
比如字段数据类型为number,传入的数据类型为varchar2,类型不同导致索引失效
(2)在索引列上进行运算与函数处理
比如where id+1=3,应改为id=3-1
比如to_char(createdatetime,‘yyyymmdd’)=to_char(sysdate,‘yyyymmdd’),应改为createdatetime>=trunc(sysdate)
避免在谓词字段上直接运算转换,应将操作转移到等于号右侧
(3)以下运算会使索引失效,应避免使用
使用 < > 、not in 、not exist、!= 、like “%_” 百分号在前
(4)查询的结果是表的大部分
这里的结果不是最后的结果,是SQL中每张表通过条件过滤后的结果。当返回的结果超过表的百分之三十时,将会选择全表扫描。
(5)在复合索引上没有使用前导列

创建索引的误区:

(1)索引和表一样应该最先被设计,而不是写一条SQL创建一条索引,SQL在编写时应主动去利用索引。
(2)复合索引与单列索引取舍的权衡,业务中的SQL利用的组合索引多还是单列索引多,二者取其一,避免单个字段创建多种类型索引造成空间浪费与解析时间的延长。
(3)单表所创建的索引不是越多越好,单表索引不得超过5个,反之在SQL解析时所花费时间将会变长,甚至有可能会选择到低效的索引。同时越多的索引会导致DML速度变慢,占用更多的磁盘空间。