您的位置:首页 > 数据库 > Oracle

Oracle数据库索引

2015-08-18 15:33 211 查看

Oracle数据库索引

  本文标签:Oracle数据库 索引 

  导读:数据库在当代社会中的地位是越来越高,干什么都似乎离不开数据库,所以,掌握好数据库是在社会中立足的条件 。如果你在数据库方面是一个新手,又或者你对Oracle数据库不是很熟悉,那你可能会发现关于索引和构建索引策略方面的讨论资料看起来很艰涩 。不过,只要你对于能满足数据库管理员日常管理相关的选项稍加注意,其实要入手还是很容易的 。

  1)b-tree索引

  Oracle数据库中最常见的索引类型是b-tree索引,也就是B-树索引,以其同名的计算科学结构命名 。每当你发布基本的没有经过进一步修改的CREATEINDEX语句时,就是在创建b-tree索引 。这里不打算对b-tree索引进行更多深入的探讨,这些用户都可以自己了解 。基本上这些索引存储你创建的索引所在的列值以及用来查找自身行的指向实际数据表的指针 。记住,这也就意味着要进行多路查询,其中一个查询各个节点和索引的叶节点,然后才是表的行自身 。这就是为什么Oracle的优化器在某种情况下会选择执行全表扫描而不执行索引查找的原因了,因为全表扫描执行起来实际上可能会更快一些 。还要注意的是,如果你的索引是创建在多个列上的话,那么第一列(leadingcolumn)非常重要 。假设你有一个多列索引(也称为级联索引),索引列的排列顺序是c列到d列,你可以对使用该索引c列单独进行一次查询,但你不能使用该索引对d列冶金行一次单独的查询 。

  2)基于函数的索引

  如果在搜索时你读取很多行,或者你的索引选择性不大,又或者你在级联索引中使用了第一列以外的列,Oracle数据库有时候会选择不使用索引 。那么如果你想要执行一个大小写不敏感的搜索呢?像下面的指令:WHEREUPPER(first_name)=
"JOHN" 。

  这也不会使用first_name字段上的索引 。为什么?因为Oracle不得不将UPPER函数用在该索引所有(ALL)的值上,所以还不如做一次全表扫描 。所以,很多时候Oracle创建基于函数的索引就是为了这个目的 。

  3)反转关键字索引

  你还可以看到这些反转关键字索引,而且不时还要用到这些索引 。假设有一列包含了“餐厅甲”、“餐厅乙”、“餐厅丙”等类似名字 。可能这不是一个很好的例子,不过关键的一点是拥有很多唯一值,但其关键字的前面一部分变化不大 。因为Oracle会在将REVERSE关键字指定给b-tree前把REVERSE字符串简化,所以使用反转关键字索引可能是最好的 。这样的一个索引可能更平衡、有用,搜索起来更快 。

  更多外部索引类型

  Oracle还提供了很多更为复杂的索引类型 。不过请注意,你最好全面阅读过相关的说明文档后再使用这些索引,因为它们各自都有各自特定的适用范围

  1)位图索引(bitmapindex)

  假设数据库表中有一列其选择性非常窄,例如性别列,该用什么类型的索引?你可能会考虑对其使用位图索引 。因为位图索引正是为相异值很少的列而创建的 。但需要考虑的因素还不只这些 。一般而言,只有当你对表中值相宜度较小的多个不同的列都使用位图索引,这样位图索引才有用,因为你可以一起使用这些索引才能对列产生更大的选择性,否则你还是需要对这些列进行一次全表扫描 。例如,对于性别列,其索引只能有两个唯一值,那么用这个索引对表的任何搜索有可能都返回一半的记录 。其次,这些索引是为数据仓库设计的,所以其假定条件是数据不会发生很大的改变 。这些索引不能用来满足事务数据库或更新频繁的数据库 。应该说,对位图索引的表进行更新根本没有一点效率

  2)位图连接索引(bitmap join index)

  位图连接索引比位图索引更进了一步 。这些索引将位图化的列完全从表数据中抽取出来,并将其存储在索引中 。其假定条件是这些列集合必须一起查询 。同样的,这也是为数据仓库数据库而设计的 。除了在句法最后有一个WHERE子句之外,位图连接索引的创建指令就像创建位图索引的CREATEBITMAPINDEX一样 。

  3)压缩索引

  压缩索引实际是标准b-tree索引的一个选项 。压缩索引的叶节点更少,所以总的I/O数量和需要的缓存也更少 。这些都意味着Oracle的优化器更可能使用这些压缩索引,而不倾向于使用标准的非压缩索引 。不过,这些好处也是有代价的,当你对这些压缩索引进行存取操作时,要消耗更多的CPU来进行解压缩 。而且,当你阅读关于优化器如何使用这些索引,又是如何选择合适的压缩级别的资料时,就开始变得晦涩了 。不同的用户不同的设置从压缩索引中得到的好处也可能会有所不同 。

  4)降序索引(descending index)

  这是基于函数索引的一种特殊类型 。降序索引可以显著优化ORDER BY x, y, z DESC子句查询的 。

  5)分区索引(partitioned index)

  如果你的数据库中有一个分区表,你就有机会体验几种新的索引类型,从贯穿所有分区的全局分区索引(global)和集中于各个单独分区的本地分区索引(local) 。这里不再进行赘述,想知道细节问题可以查询相关文献 。

  6)索引组织表(index organized table,IOT)

  这是在Oracle9i中引进的一种新类型表 。Oracle会将级联索引及其扩展类型的索引用于表中所有的列 。当所有数据都载入到索引结构之后,表就成多余的了,你尽可以将表本身删除掉 。这就是索引组织表 。

  7)簇索引(cluster index)

  基本上,簇索引就是将多个表的相同列放在一起,而对该列使用用一个簇索引 。这种索引在实际应用比较少,因为还有各种有待解决性能问题存在 。

  8)域索引(domain index)

  当我们创建为用户定义数据类型(datatype)创建用户自定义索引类型(indextype)时就要使用域索引 。

  9)隐藏索引(invisible index)

  这是Oracle11g中推出的新特性 。其创建过程和标准索引一样,但创建后对于基于代价的优化器(CBO)是不可见的 。这可以让你对性能进行大型测试查询,而不会影响现有的正在运行的应用程序

  10)虚拟索引(virtual index)

  这是为测试人员和开发人员准备的又一个工具 。虚拟索引(不分配段空间)可以让你在不需要实际创建索引的情况下,测试新索引及其对查询计划的影响 。对于GB级的表来说,构建索引非常耗费资源而且还要占用大量时间

  11)其他的索引类型

  Oracle数据库还提供了很多其他类型的索引,例如用来为字符型大型二进制对象(CLOB)或其他大型文本数据构建索引的OracleTEXT,OracleSpatial等 。有兴趣的读者可以自己查找相关资料了解 。

  都是为了优化器

  如果你曾经广泛接触过MySQL和其他的数据库,你会发现甲骨文虽然是全球领先的数据库供应商,但它们的数据库对于用户来说用起来其实并不是很方便 。提到优化器这个问题可能有点离题了,不过Oracle数据库最基本的食料就是优化器了,这的确是种挺特别的调料,而且变得越来越美味了 。市面上有很多以Oracle基于代价的优化器(CostBasedOptimizer,CBO)为主题内容的书籍,专门介绍分析表和索引的技巧和策略 。

  对于数据库,除了需要一直更新你的统计信息之外,你可能还需要不断测试新的查询 。使用解析计划机制,并进行优化以便减少总I/O量以及排序合并数据的计算量,只有这样你才能获得更好的性能表现 。

  总结

  上文主要讲述了Oracle数据库索引的基本知识,对刚刚入门的初学者是很好的学习资料 。虽然Oracle数据库的索引世界有点吓人,不过实际上你平常经常使用的索引就只有那么一些 。而且,不管唱反调的人怎样诋毁,Oracle的优化器都已经设计相当出色;总体而言,Oracle很擅长于让你的数据库运行地更有效率 。虽然这并不意味着你不需要对自己的SQL进行调优,不过,如果你一直保持着最新的统计信息,并让Oracle为你整理出你所需要的最小数据集的话,它能够以极快的速度满足你的需要 。

在关系数据库中,索引是一种与表有关的数据库结构,它可以使对应于表的SQL语句执行得更快。索引的作用相当于图书的目录,可以根据目录中的页码快速找到所需的内容。

对于数据库来说,索引是一个必选项,但对于现在的各种大型数据库来说,索引可以大大提高数据库的性能,以至于它变成了数据库不可缺少的一部分。

索引分类:
逻辑分类
single column or concatenated    对一列或多列建所引
unique or nonunique    唯一的和非唯一的所引,也就是对某一列或几列的键值(key)是否是唯一的。
Function-based   基于某些函数索引,当执行某些函数时需要对其进行计算,可以将某些函数的计算结果事先保存并加以索引,提高效率。
Doman   索引数据库以外的数据,使用相对较少

物理分类
B-Tree :normal or reverse key B-Tree索引也是我们传统上常见所理解的索引,它又可以分为正常所引和倒序索引。
Bitmap : 位图所引,后面会细讲

B-Tree 索引

  B-Tree index 也是我们传统上常见所理解的索引。B-tree (balance tree)即平衡树,左右两个分支相对平衡。
B-Tree index



Root为根节点,branch 为分支节点,leaf 到最下面一层称为叶子节点。每个节点表示一层,当查找某一数据时先读根节点,再读支节点,最后找到叶子节点。叶子节点会存放index entry (索引入口),每个索引入口对应一条记录。
Index entry 的组成部分:
Indexentry entry header   存放一些控制信息。
Key column length   某一key的长度
Key column value    某一个key 的值
ROWID   指针,具体指向于某一个数据

创建索引:

用户登录:
SQL> conn as1/as1
Connected.

创建表:
SQL> create table dex (id int,sex char(1),name char(10));
Table created.

向表中插入1000条数据
SQL> begin
2  for i in 1..1000
3  loop
4  insert into dex values(i,'M','chongshi');
5  end loop;
6  commit;
7  end;
8  /

PL/SQL procedure successfully completed.

查看表记录
SQL> select * from dex;
ID SE NAME
---------- -- --------------------
... . .....

991 M  chongshi
992 M  chongshi
993 M  chongshi
994 M  chongshi
995 M  chongshi
996 M  chongshi
997 M  chongshi
998 M  chongshi
999 M  chongshi
1000 M  chongshi

1000 rows selected.

创建索引:
SQL> create index dex_idx1 on dex(id);
Index created.
注:对表的第一列(id)创建索引。

查看创建的表与索引
SQL> select object_name,object_type from user_objects;

OBJECT_NAME                  OBJECT_TYPE
--------------------------------------------------------------------------------
DEX                           TABLE
DEX_IDX1                      INDEX


  索引分离于表,作为一个单独的个体存在,除了可以根据单个字段创建索引,也可以根据多列创建索引。Oracle要求创建索引最多不可超过32列。

SQL> create index dex_index2 on dex(sex,name);
Index created.

SQL>  select object_name,object_type from user_objects;

OBJECT_NAME                           OBJECT_TYPE
--------------------------------------------------------------------------------
DEX                                       TABLE
DEX_IDX1                                 INDEX
DEX_INDEX2                               INDEX


这里需要理解:
  编写一本书,只有章节页面定好之后再设置目录;数据库索引也是一样,只有先插入好数据,再建立索引。那么我们后续对数据库的内容进行插入、删除,索引也需要随之变化。但索引的修改是由oracle自动完成的。



上面这张图能更加清晰的描述索引的结构。
跟节点记录0至50条数据的位置,分支节点进行拆分记录0至10.......42至50,叶子节点记录每第数据的长度和值,并由指针指向具体的数据。
最后一层的叶子节是双向链接,它们是被有序的链接起来,这样才能快速锁定一个数据范围。
如:

SQL> select * from dex where id>23 and id<32;

ID SE NAME
---------- -- --------------------
24 M  chongshi
25 M  chongshi
26 M  chongshi
27 M  chongshi
28 M  chongshi
29 M  chongshi
30 M  chongshi
31 M  chongshi

8 rows selected.


  如上面查找的列子,通过索引的方式先找到第23条数据,再找到第32条数据,这样就能快速的锁定一个查找的范围,如果每条数据都要从根节点开始查找的话,那么效率就会非常低下。

位图索引

  位图索引主要针对大量相同值的列而创建。拿全国居民登录一第表来说,假设有四个字段:姓名、性别、年龄、和身份证号,年龄和性别两个字段会产生许多相同的值,性别只有男女两种值,年龄,1到120(假设最大年龄120岁)个值。那么不管一张表有几亿条记录,但根据性别字段来区分的话,只有两种取值(男、女)。那么位图索引就是根据字段的这个特性所建立的一种索引。
Bitmap Index



  从上图,我们可以看出,一个叶子节点(用不同颜色标识)代表一个key , start rowid 和 end rowid规定这种类型的检索范围,一个叶子节点标记一个唯一的bitmap值。因为一个数值类型对应一个节点,当时行查询时,位图索引通过不同位图取值直接的位运算(与或),来获取到结果集合向量(计算出的结果)。

举例讲解:
假设存在数据表T,有两个数据列A和B,取值如下,我们看到A和B列中存在相同的数据。



对两个数据列A、B分别建立位图索引:idx_t_bita和idx_t_bitb。两个索引对应的存储逻辑结构如下:
Idx_t_bita索引结构,对应的是叶子节点:



Idx_t_bitb索引结构,对应的是叶子节点:



对查询“select * from t where b=1 and (a=’L’ or a=’M’)”
分析:位图索引使用方面,和B*索引有很大的不同。B*索引的使用,通常是从根节点开始,经过不断的分支节点比较到最近的符合条件叶子节点。通过叶子节点上的不断Scan操作,“扫描”出结果集合rowid。
而位图索引的工作方式截然不同。通过不同位图取值直接的位运算(与或),来获取到结果集合向量(计算出的结果)。
针对实例SQL,可以拆分成如下的操作:
1、a=’L’ or a=’M’
a=L:向量:1010
a=M:向量:0001
or操作的结果,就是两个向量的或操作:结果为1011。

2、结合b=1的向量
中间结果向量:1011
B=1:向量:1001
and操作的结果,1001。翻译过来就是第一和第四行是查询结果。

3、获取到结果rowid
目前知道了起始rowid和终止rowid,以及第一行和第四行为操作结果。可以通过试算的方法获取到结果集合rowid。

位图索引的特点
1.Bitmap索引的存储空间节省
2.Bitmap索引创建的速度快
3.Bitmap索引允许键值为空
4.Bitmap索引对表记录的高效访问

创建位图索引:

查看表记录
SQL> select * from dex;
...................
ID SEX NAME
---------- -- --------------------
991 M  chongshi
992 M  chongshi
993 G  chongshi
994 G  chongshi
995 G  chongshi
996 M  chongshi
997 G  chongshi
998 G  chongshi
999 G  chongshi
1000 M  chongshi

1000 rows selected.

对于上面表来说sex(性别)只有两种值,最适合用来创建位图所引
创建索引:
SQL> create bitmap index my_bit_idx on dex(sex);

Index created.

查看创建的所引
SQL>  select object_name,object_type from user_objects;

OBJECT_NAME                           OBJECT_TYPE
--------------------------------------------------------------------------------
MY_BIT_IDX                               INDEX


创建索引的一些规则

1、权衡索引个数与DML之间关系,DML也就是插入、删除数据操作。
这里需要权衡一个问题,建立索引的目的是为了提高查询效率的,但建立的索引过多,会影响插入、删除数据的速度,因为我们修改的表数据,索引也要跟着修改。这里需要权衡我们的操作是查询多还是修改多。
2、把索引与对应的表放在不同的表空间。
当读取一个表时表与索引是同时进行的。如果表与索引和在一个表空间里就会产生资源竞争,放在两个表这空就可并行执行。
3、最好使用一样大小是块。
Oracle默认五块,读一次I/O,如果你定义6个块或10个块都需要读取两次I/O。最好是5的整数倍更能提高效率。
4、如果一个表很大,建立索引的时间很长,因为建立索引也会产生大量的redo信息,所以在创建索引时可以设置不产生或少产生redo信息。只要表数据存在,索引失败了大不了再建,所以可以不需要产生redo信息。

5、建索引的时候应该根据具体的业务SQL来创建,特别是where条件,还有where条件的顺序,尽量将过滤大范围的放在后面,因为SQL执行是从后往前的。(小李飛菜刀)

索引常见操作

改变索引

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条记录,这时一个块被清空,总的数据条数才会减少。

在向大家详细介绍Oracle建表之前,首先让大家了解下Oracle索引,因为好的索引能帮助Oracle数据库更好的检索我们想要的信息。

Oracle索引逻辑上:

Single column 单行索引

Concatenated 多行索引

Unique 唯一索引

NonUnique 非唯一索引

Function-based函数索引

Domain 域索引

Oracle索引物理上:

Partitioned 分区索引

NonPartitioned 非分区索引

B-tree:

Normal 正常型B树

Rever Key 反转型B树

Bitmap 位图索引

Oracle索引结构:

B-tree:

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

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

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

典型的树状结构;

每个结点都是数据块;

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

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

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

Bitmap:

适合与决策支持系统;

做UPDATE代价非常高;

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

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

树型结构:

索引头

开始ROWID,结束ROWID(先列出索引的最大范围)

BITMAP

每一个BIT对应着一个ROWID,它的值是1还是0,如果是1,表示着BIT对应的ROWID有值;

B*tree索引的话通常在访问小数据量的情况下比较适用,比如你访问不超过表中数据的5%,当然这只是个相对的比率,适用于一般的情况。bitmap的话在数据仓库中使用较多,用于低基数列,比如性别之类重复值很多的字段,基数越小越好。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: