小蒜头's Blog

Happy coding

小议在Oracle中索引的使用

小蒜头 posted @ 2013年4月02日 20:46 in [Oracle数据库] , 1192 阅读

    索引是由Oracle维护的可选结构,为数据提供快速的访问。准确地判定在什么地方需要使用索引是困难的,使用索引有利于调节检索速度。 当建立一个索引时,必须指定用于跟踪的表名以及一个或多个表列。一旦建立了索引,在用户表中建立、更改和删除数据库时, Oracle就自动地维护索引。

创建索引时,下列准则将帮助用户做出决定: 

1) 索引应该在SQL语句的"where"或"and"部分涉及的表列(也称谓词)被建立。假如  personnel表的"firstname"表列作为查询结果显示,而不是作为谓词部分,则不论其值是什么,该表列不会被索引。  

2)用户应该索引具有一定范围的表列,索引时有一个大致的原则:假如表中列的值占该表中行的20%以内,这个表列就可以作为候选索引表列。假设一个表有36 000行且表中一个表列的值平均分布(大约每12000行),那么该表列不适合于一个索引。然而,假如同一个表中的其他表列中列值的行在1 0 0 0~1 5 0 0之间(占3 %~4 % ),则该表列可用作索引。  

3)假如在SQL语句谓词中多个表列被一起连续引用,则应该考虑将这些表列一起放在一个索引内, Oracle将维护单个表列的索引(建立在单一表列上)或复合索引(建立在多个表列上)。复合索引称并置索引。  

1 主要害字的约束   

关系数据库理论指出,在表中能唯一标识表的每个数据行的一个或多个表列是对象的主要害字。由于数据字典中定义的主要害字能确保表中数据行之间的唯一性,因此,在Oracle 8 i数据库中建立表索引要害字有助于应用调节。另外,这也减轻了开发者为了实现唯一性检查,而需要各自编程的要求。  

提示使用主要害字索引条目比不使用主要害字索引检索得快。  

假设表person把它的i d表列作为主要害字,用下列代码设置约束: alter table person add constraint person_pk PRimary key (id) using index storage (initial 1m next 1m pctincrease 0) tablespace prd_indexes ;   

处理下列SQL语句时: select last_name ,first_name ,salary from person where id = 289 ;   

在查找一个已确定的“ id”表列值时, Oracle将直接找到person_pk。假如其未找到正确的索引条目,Oracle知道该行不存在。主要害字索引具有下列两个独特之处:  

1.1因为索引是唯一的, 所以Oracle知道只有一个条目具有设定值。假如查找到了所期望的条目,则立即终止查找。  

1.2一旦碰到一个大于设定值的条目,索引的顺序搜索可被终止;   

2 ORDER BY中用索引   

ORDER BY 子句只在两种严格的条件下使用索引.   

ORDER BY中所有的列必须包含在相同的索引中并保持在索引中的排列顺序.   

ORDER BY中所有的列必须定义为非空.   

WHERE子句使用的索引和ORDER BY子句中所使用的索引不能并列.   

例如:   表DEPT包含以下列: DEPT_CODE PK

NOT NULL DEPT_DESC NOT NULL DEPT_TYPE NULL   非唯一性的索引(DEPT_TYPE)   

低效: (索引不被使用) SELECT DEPT_CODE FROM DEPT ORDER BY DEPT_TYPE EXPLAIN PLAN: SORT ORDER BY TABLE access FULL   

高效: (使用索引) SELECT DEPT_CODE FROM DEPT WHERE DEPT_TYPE > 0 EXPLAIN PLAN: TABLE ACCESS BY ROWID ON EMP INDEX RANGE SCAN ON DEPT_IDX   

3 避免改变索引列的类型.   

当比较不同数据类型的数据时, ORACLE自动对列进行简单的类型转换. 假设 EMPNO是一个数值类型的索引列. SELECT … FROM EMP WHERE EMPNO = ‘123'   

实际上,经过ORACLE类型转换, 语句转化为: SELECT … FROM EMP WHERE EMPNO = TO_NUMBER(‘123')   

幸运的是,类型转换没有发生在索引列上,索引的用途没有被改变.   

现在,假设EMP_TYPE是一个字符类型的索引列.

SELECT … FROM EMP WHERE EMP_TYPE = 123   

这个语句被ORACLE转换为: SELECT … FROM EMP WHERE TO_NUMBER(EMP_TYPE)=123   因为内部发生的类型转换, 这个索引将不会被用到! 为了避免ORACLE对你的SQL进行隐式的类型转换, 最好把类型转换用显式表现出来. 注重当字符和数值比较时, ORACLE会优先转换数值类型到字符类型.   

4 需要当心的WHERE子句   

某些SELECT 语句中的WHERE子句不使用索引. 这里有一些例子.   

在下面的例子里, ‘!=' 将不使用索引. 记住, 索引只能告诉你什么存在于表中, 而不能告诉你什么不存在于表中.   

不使用索引: SELECT ACCOUNT_NAME FROM TRANSACTION WHERE AMOUNT !=0;   

使用索引: SELECT ACCOUNT_NAME FROM TRANSACTION WHERE AMOUNT >0;   

下面的例子中, ‘'是字符连接函数. 就象其他函数那样, 停用了索引.

不使用索引:

SELECT ACCOUNT_NAME,AMOUNT FROM TRANSACTION WHERE ACCOUNT_NAME ='AMEXA';   

使用索引: SELECT ACCOUNT_NAME,AMOUNT FROM TRANSACTION WHERE ACCOUNT_NAME = ‘AMEX' AND ACCOUNT_TYPE=' A';   

下面的例子中, ‘+'是数学函数. 就象其他数学函数那样, 停用了索引.   

不使用索引: SELECT ACCOUNT_NAME, AMOUNT FROM TRANSACTION WHERE AMOUNT + 3000 >5000;   

使用索引: SELECT ACCOUNT_NAME, AMOUNT FROM TRANSACTION WHERE AMOUNT > 2000 ;   

下面的例子中,相同的索引列不能互相比较,这将会启用全表扫描.  

不使用索引: SELECT ACCOUNT_NAME, AMOUNT FROM TRANSACTION WHERE ACCOUNT_NAME = NVL(:ACC_NAME,ACCOUNT_NAME);   

使用索引: SELECT ACCOUNT_NAME, AMOUNT FROM TRANSACTION WHERE ACCOUNT_NAME LIKE NVL(:ACC_NAME,'%');   

假如一定要对使用函数的列启用索引, ORACLE新的功能: 基于函数的索引(Function-Based Index) 也许是一个较好的方案. CREATE INDEX EMP_I ON EMP (UPPER(ename)); /*建立基于函数的索引*/ SELECT * FROM emp WHERE UPPER(ename) = ‘BLACKSNAIL'; /*将使用索引*/   

5 怎样监控无用的索引   

Oracle 9i以上,可以监控索引的使用情况,假如一段时间内没有使用的索引,一般就是无用的索引

语法为:  

开始监控:alter index index_name monitoring usage;   

检查使用状态:select * from v$object_usage;   

停止监控:alter index index_name nomonitoring usage;   

当然,假如想监控整个用户下的索引,可以采用如下的脚本:

set heading off

set echo off

set feedback off

set pages 10000

spool start_index_monitor.sql

SELECT 'alter index 'owner'.'index_name' monitoring usage;' FROM dba_indexes WHERE owner = USER;

spool off

set heading on

set echo on

set feedback on ------------------------------------------------

set heading off

set echo off

set feedback off

set pages 10000

spool stop_index_monitor.sql

SELECT 'alter index 'owner'.'index_name' nomonitoring usage;' FROM dba_indexes WHERE owner = USER;

spool off

set heading on

set echo on

set feedback on


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter