关于索引的一点知识

索引可能是我们对于数据库性能优化最常用的一个手段。这里简单说下里面的几个方面的问题。

 

1、  索引是一个对象;

索引是一个独立的数据库对象,和数据表table一样。在Oracle中,数据库对象object都是通过段segment结构表示。我们在数据字典dba_segment中,可以使用索引的名称搜索出与segment_name相等的字典项目。

 

SQL> select segment_name, segment_type, bytes, blocks, extents from dba_segments where segment_name='IND_T_OWNER_NAME';

 

SEGMENT_NAME         SEGMENT_TYPE         BYTES     BLOCKS    EXTENTS

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

IND_T_OWNER_NAME     INDEX              3145728        384         18

 

上述就说明,该数据段对象IND_T_OWNER_NAME,对应的类型为索引。占据空间为3145728 bytes,约为3.16M的空间,对应384个数据块,包括在18个数据区中。

 

在堆表结构中,数据表和索引是可以分开进行存储的。通常,从性能角度考虑我们常将两者放置在不同的Tablespace中,这样做的目的主要是为了分散物理IO。

 

 

2、  索引是有代价的

索引的建立通常是为提高数据检索的效率。使用索引搜索的一个目的是避免全表扫描FTS,提高搜索效率。进行索引搜索时,实际上先进行一次索引结构读取,获取查询结果所在数据块的物理地址ROWID,之后进行第二次检索数据表块,直接获取到数据行信息。所以,在数据表较大,结果集较少的时候,通常进行索引检索的效率较好。反之,如果返回数据较多,例如返回整个大表的绝大部分记录行,这样往往是全表扫描的效果较好。

 

在现有的Oracle版本中,使用的CBO(基于成本的优化器)就是进行检索方案的选择确定。究竟是何种方案,要根据收集到的统计进行进行一系列的计算估算,最后确定执行计划。

 

当索引对象生效的时候,会实时保证和数据表的索引列同步。如果发生增加、修改和删除操作,索引也要进行相应的结构变化和修改,用来适应数据表结构的变化。所以,加入索引后,为了维护索引的完整性,增加、修改和删除等DML操作性能会受到一定程度的影响。

 

另一方面,作为一个独立的数据库对象,索引也是要消耗存储空间的。如果对应的数据表很大的话,相应索引的体积可以会达到一定程度。相应的,重建索引的效率也就成为不能忽视的一个问题。

 

总之,索引技术是一个使用空间和DML效率为交换,换高效检索的技术方案。

 

3、  索引的状态

 

从索引的数据字典上,我们可以看到数据索引的状态。

 

SQL> select index_name, index_type, status, leaf_blocks from dba_indexes where index_name='IND_T_OWNER_NAME';

 

INDEX_NAME                     INDEX_TYPE                  STATUS   LEAF_BLOCKS

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

IND_T_OWNER_NAME               NORMAL                      VALID            287

 

索引的状态只有两个,VALID和UNUSABLE。Valid表示当前索引正在生效,会实时保证与数据表的一致性,如果发生DML操作,其内部结构会自动进行调整。一些带有约束特定的索引,如unique,也会起到数据完整性保持的作用。

 

另一个索引状态Unusable,表示当前索引停用。索引是不会和数据表联动的更新结构,也不会起到数据完整性保持的作用。

 

实际工作中,我们可以选择暂时禁用索引功能,来提高数据表插入、修改效率。因为,在索引起作用的情况下,大量数据的DML操作会带来很多的索引更新和Redo Log的生成。这在批量数据加载的时候是不需要的。所以,可以暂时禁用索引。

 

SQL> alter index ind_t_owner_name unusable;

 

Index altered

 

查看索引状态:

 

SQL> select index_name, index_type, status, leaf_blocks from dba_indexes where index_name='IND_T_OWNER_NAME';

 

INDEX_NAME                     INDEX_TYPE                  STATUS   LEAF_BLOCKS

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

IND_T_OWNER_NAME               NORMAL                      UNUSABLE         287

 

Executed in 0.03 seconds

 

此时进行一系列的操作,是不会更新索引的。同时,一些操作,也不会走索引的执行计划。

 

SQL> select * from t where object_name='T' and wner='SYS';

 

已用时间:  00: 00: 00.26

 

执行计划

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

Plan hash value: 1601196873

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

| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |

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

|   0 | SELECT STATEMENT  |      |     1 |    92 |   156   (2)| 00:00:02 |

|*  1 |  TABLE ACCESS FULL| T    |     1 |    92 |   156   (2)| 00:00:02 |

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

Predicate Information (identified by operation id):

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

   1 - filter("OBJECT_NAME"='T' AND "OWNER"='SYS')

 

统计信息

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

        386  recursive calls

          0  db block gets

        758  consistent gets

        545  physical reads

        116  redo size

       1194  bytes sent via SQL*Net to client

        385  bytes received via SQL*Net from client

          2  SQL*Net roundtrips to/from client

          5  sorts (memory)

          0  sorts (disk)

          1  rows processed

 

如果我们强制使用hint,要求执行索引路径时,是会出现错误提示的。

 

SQL> select /*+ index(t ind_t_owner_name) */* from t where object_name='T' and wner='SYS';

 

select /*+ index(t ind_t_owner_name) */* from t where object_name='T' and wner='SYS'

 

ORA-01502: 索引 'SYS.IND_T_OWNER_NAME' 或这类索引的分区处于不可用状态

 

只有进行索引的重建rebuild,才可以实现索引状态的恢复和启用。

 

SQL> alter index ind_t_owner_name rebuild;

 

Index altered

 

Executed in 0.611 seconds

 

SQL> select index_name, index_type, status, leaf_blocks from dba_indexes where index_name='IND_T_OWNER_NAME';

 

INDEX_NAME                     INDEX_TYPE                  STATUS   LEAF_BLOCKS

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

IND_T_OWNER_NAME               NORMAL                      VALID            287

 

Executed in 0.06 seconds

 

SQL> select /*+ index(t ind_t_owner_name) */ object_name from t where object_name='T' and wner='SYS';

 

OBJECT_NAME

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

T

 

Executed in 0.02 seconds

 

默认也会将索引考虑入执行计划:

 

SQL> select * from t where object_name='T' and wner='SYS' ;

 

已用时间:  00: 00: 00.01

 

执行计划

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

Plan hash value: 1404465244

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

| Id  | Operation                   | Name             | Rows  | Bytes | Cost (%CPU)| Time     |

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

|   0 | SELECT STATEMENT            |                  |     1 |    92 |     2 (0)| 00:00:01 |

|   1 |  TABLE ACCESS BY INDEX ROWID| T                |     1 |    92 |     2 (0)| 00:00:01 |

|*  2 |   INDEX RANGE SCAN          | IND_T_OWNER_NAME |     1 |       |     1 (0)| 00:00:01 |

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

Predicate Information (identified by operation id):

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

   2 - access("OWNER"='SYS' AND "OBJECT_NAME"='T')

 

统计信息

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

          1  recursive calls

          0  db block gets

          4  consistent gets

          0  physical reads

          0  redo size

       1198  bytes sent via SQL*Net to client

        385  bytes received via SQL*Net from client

          2  SQL*Net roundtrips to/from client

          0  sorts (memory)

          0  sorts (disk)

          1  rows processed

 

有一点额外的也要注意,如果使用的是唯一索引unique类型,在从unusable转变为valid的过程中,要进行数据列的一个检查。如果发现列的值已经不满足唯一性条件,则报错,并且索引状态不会发生变化。

 

除了手工进行索引的状态变化之外,一些管理操作,如move、分区表操作,也会影响到索引的状态。实际中可能需要进行rebuild工作,对一些比较大的数据表,rebuild工作的时间可能也会比较长。

 

 

4、  索引的监控

无论是投产之后还是开发测试中,我们都在数据表中加入了一些索引。通常我们是不能实时监视每条语句的执行计划,那么有没有一些手段可以监控索引的执行情况,发现一些不常用的索引,定位优化目标呢?

 

答案是肯定的。在oracle中,可以借助monitoring usage关键字和v$object_usage视图实现这个功能。

 

启用监控功能并且收集监控结果。

 

SQL> alter index ind_t_owner_name monitoring usage;

 

Index altered

 

 

SQL> select /*+ index(t ind_t_owner_name) */ object_name from t where object_name='T' and wner='SYS';

 

OBJECT_NAME

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

T

 

Executed in 0.01 seconds

 

SQL> select * from v$object_usage where index_name='IND_T_OWNER_NAME';

 

INDEX_NAME           TABLE_NAME MONITORING USED START_MONITORING    END_MONITORING

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

IND_T_OWNER_NAME     T          YES        YES  12/07/2010 23:33:36

 

Executed in 0.01 seconds

 

收集所有的相关视图信息,可以方便的找出哪个Index是一直没有使用过的,也就可以进一步定位到相应功能和SQL语句。

 

关闭监控功能:

 

SQL> alter index ind_t_owner_name nomonitoring usage;

 

Index altered

 

Executed in 0.01 seconds

 

 

5、  索引的管理

在最近看的一本书中,提出了一个比较新的索引管理思路,觉得值得借鉴。

 

我们建索引是一项有代价的工作,牺牲DML操作来实现索引的同步。那么,我们如果确定加什么索引,什么时候加索引。本质上还要看系统怎么使用数据表,更进一步是传入的SQL结构是一个什么样子,根据这些信息进行索引的管理。

 

同时,在DBA的工作中,要加入索引信息维护追踪的机制。那个索引对应那个模块的那个需求而建立,当这个需求变化或者弱化后,索引要随之发生变化。不能残留很多各种原因建立的索引。这样是给SQL执行计划带来很多问题。在CBO时代,积极的更新统计信息大部分时候要比强制用hint有效的多。

 

上述是几点拙见,忘路过之高人不吝指教。001.gif

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/17203031/viewspace-681121/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/17203031/viewspace-681121/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值