• 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 的组成部分:

    Index entry header 存放一些控制信息。

    Key column length 某一 key 的长度

    Key column value 某一个 key 的值

    ROWID 指针,具体指向于某一个数据

    创建索引:

    用户登录:

    SQL> conn test/test
    

      

    创建表:

    SQL> create table test (id number,sex char(1),name varchar2(10)); 
    

      

    向表中插入 1000 条数据

    SQL> begin
    for i in 1..1000
    loop
    insert into test values(i,'M','test_table'); 
    end loop; commit; end;

      

    查看表记录

    SQL> select * from test;
    

      

    接下来创建索引

    创建索引:

    SQL> create index test_idx1 on test(id);

    注:对表的第一列(id)创建索引,索引名test_idx1。

    查看创建的表与索引

    SQL> select object_name,object_type from user_objects;
    
    OBJECT_NAME               OBJECT_TYPE
    ------------------------- -------------------
    TEST_IDX1                 INDEX
    TEST                      TABLE
    

      

    索引分离于表,作为一个单独的个体存在,除了可以根据单个字段创建索引,也可以根据多列创建索引。

    Oracle 要求创建索引最多不可超过 32 列。

    SQL> create index test_idx2 on test(sex,name);
    
    SQL> select object_name,object_type from user_objects;
    
    OBJECT_NAME               OBJECT_TYPE
    ------------------------- -------------------
    TEST_IDX2                 INDEX
    TEST_IDX1                 INDEX
    TEST                      TABLE
    

      

    这里需要理解:

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

    上面这张图能更加清晰的描述索引的结构。

    跟节点记录 0 至 50 条数据的位置,分支节点进行拆分记录 0 至 10.......42 至 50,叶子节点记录每条数据的长度和值,并由指针指向具体的数据。

    最后一层的叶子节是双向链接,它们是被有序的链接起来,这样才能快速锁定一个数据范围。

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

    如上面查找的列子,通过索引的方式先找到第 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 索引对表记录的高效访问

    什么情况下应该使用位图索引?

    位图索引适合只有几个固定值的列,如性别、婚姻状况、行政区等等,而身份证号这种类型不适合用位图索引,如果用户查询的列的相异基数非常的小,要为这些相异基数值比较小的列建索引,就需要建立位图索引。

    那么何谓相异基数非常的小?可以认为行集中不同项的个数除以行数应该是一个很小的数(接近0),例如,某个列(性别)可能取值为M、F、null.如果一个表中有20000条数据,那么3/20000=0.00015,那么这就算是个相异基数很小的情况,类似的,如果有100000个不同的值,与10000000条结果相比,比值是0.01,同样也很小,也可以认为是相异基数很小的情况,都可以建立位图索引;

    位图索引的限制或者说是弊端

    位图索引在读密集的环境中能很好地工作,但是对于写密集的环境则极不适合,原因在于,一个位图索引键条目(可以理解为前面的男 、女、未婚、已婚等)指向多行。如果一个会话修改了有索引的列的数据,那么大多数情况下,这个索引条目只想的所有行都会被锁定。oracle无法锁定一个位图索引条目中的单独一位,而是会锁定整个位图索引条目,倘若其他会话修改也需要更新同样的这个位图索引条目,就会被“关在门外”,这样就大大影响了并发性,因为每个更新都有可能锁定数百行,不允许并发地更新他们的位图列;

    举个例子说明:有这样一个字段job,记录各个员工的职位如:dba 、java、php等等 ,假设我们在这个job列上建立了位图索引。假如rowid=100的员工职业为php,rowid=120的员工职业为php;

    如果会话1使用update更新某个员工的职位(job),比如update table set table.job='dba' where rowid=100;,但还没有commit,而会话2也使用update更新另一个员工的职位,update table set table.job='dba' where rowid=120; 这个时候会话2怎么也更新不了,需要等待会话1 commit。

    原因:会话1更新rowid=100的这个员工的职位,假如这个员工原来是php,现在改成dba,那么在commit之前,就会锁定所有job=php和job=dba的所有行,所以当会话2尝试更新job=dba只能等待锁,只有commit之后才解锁。这样就大大影响了并发性;

    总结:

    位图索引是为数据仓库(也就是查询环境设计的);

    位图索引特别不适合OLTP系统;

    位图索引不适合与dml频繁的环境;

    位图索引适用于DSS系统;

    位图索引不适合频繁修改的系统;

    弊端是严重影响并发性,因为update索引列值的时候,会锁定新值和旧值指向的所有数据行,所以使用位图索引需慎重。

    创建位图索引:

    查看表记录

    SQL> select * from itpux;
    

      

    对于上面表来说 sex(性别)只有两种值,最适合用来创建位图所引

    创建索引:

    SQL> create bitmap index my_bit_idx on itpux(sex);
    Index created.
    

      

    查看创建的索引

    SQL> select object_name,object_type from user_objects;
    

      

    创建索引的一些规则

    1、权衡索引个数与 DML 之间关系,DML 也就是插入、删除数据操作。 这里需要权衡一个问题,建立索引的目的是为了提高查询效率的,但建立的索引过多,会影响插入、删除数据的速度,因为我们修改的表数据,索引也要跟着修改。这里需要权衡我们的操作是查询多还是修改多。

    2、把索引与对应的表放在不同的表空间。

    当读取一个表时,表与索引是同时进行的。如果表与索引和在一个表空间里就会产生资源竞争,放在两个表这空就可并行执行。

    3、最好使用一样大小是块。

    Oracle 默认五块,读一次 I/O,如果你定义 6 个块或 10 个块都需要读取两次 I/O。最好是 5 的整数倍更能提高效率。

    4、如果一个表很大,建立索引的时间很长,因为建立索引也会产生大量的 redo 信息,所以在创建索引时可以设置不产生或少产生 redo 信息。只要表数据存在,索引失败了大不了再建,所以可 以不需要产生 redo 信息。

    例:

    alter index EMP_EMP_ID_PK rebuild nologging; 
    

      

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

    索引使用规则与日常操作过程

    1、改变索引

    alter index test_id_idx storage(next 400K maxextents 100);
    

      

    索引创建后,感觉不合理,也可以对其参数进行修改。

    2、重新创建索引

    alter index 索引名 rebuild

    数据库处理过程

    a.锁表

    b.创建新的临时索引

    c.删除老的索引

    d.把新的索引重命名为老的索引名字

    e.对表进行解锁

    alter index 索引名 rebuild tablespace new_tbs;
    

      

    数据库处理过程

    a.锁表

    b.创建新的临时索引到新的表空间

    c.删除老的索引

    d.把新的索引重命名为老的索引名字

    e.对表进行解锁

    alter index 索引名 rebuild online;

    数据库处理过程

    a.锁表

    b.创建临时的索引和 IOT 表用来存 on-going DML;

    普通表就存放键值,IOT 索引直接存放表中数据;

    on-going DML 就是用户所做的一些增删改操作。

    c.对表进行解锁

    d.从老的索引中创建一个新的索引

    e.将 IOT 表的内容与新创建的索引合并

    f.锁住表

    g.再次将 IOT 表的内容更新到新索引中,把老索引干提

    h.把新索引重命名为老索引的名字

    i.对表进行解锁

    额外:

    ALTER INDEX 索引名 REBUILD ONLINE vs ALTER INDEX 索引名 REBUILD;
    

      

    alter index rebuild online实质上是扫描表而不是扫描现有的索引块来实现索引的重建.

    alter index rebuild 只扫描现有的索引块来实现索引的重建。

    rebuild index online在执行期间不会阻塞DML操作,但在开始和结束阶段,需要请求模式为4的TM锁。因此,如果在rebuild index online开始前或结束时,有其它长时间的事物在运行,很有可能就造成大量的锁等待。也就是说在执行前仍会产生阻塞, 应该避免排他锁.

    而rebuild index在执行期间会阻塞DML操作, 但速度较快.

    两者重建索引时的扫描方式不同,rebuild用的是“INDEX FAST FULL SCAN”,rebuild online用的是“TABLE ACCESS FULL”;

    即rebuild index是扫描索引块,而rebuild index online是扫描全表的数据块.

    3、索引碎片

    alter index 索引名 coalesce;

    4、删除索引

    drop index 索引名;

    5、分析索引

    analyze index 索引名 validate structure;
     
    select count(*) from index_stats
     
    alter index 索引名 coalesce;
    

      

  • 相关阅读:
    SDOI2017 R2泛做
    类似静态区间逆序对的题的一些做法
    友链&&日记
    注意事项以及一些奇怪的姿势
    关于各种算法以及好的blog的整理(持续更新)
    PKUSC2019游记
    洛谷P5398 [Ynoi2018]GOSICK(二次离线莫队)
    洛谷P4887 第十四分块(前体)(二次离线莫队)
    [51nod]1678 lyk与gcd(莫比乌斯反演)
    LOJ#557. 「Antileaf's Round」你这衣服租来的吗(FHQ Treap+珂朵莉树)
  • 原文地址:https://www.cnblogs.com/black-start/p/11014363.html
Copyright © 2020-2023  润新知