3.函数索引
可以在表中创建基于函数的索引。如果没有基于函数的索引,任何在列上执行了函数的查询都不能使用这个列的索引。例如,下面的查询就不能使用DT_TIME列上的索引,除非它是基于函数的索引:
WHERE 1=1 AND (sysdate-to_date(DT_TIME,'yyyymmddhh24miss'))*24*60<10
在DT_TIME上面加上了索引,但是发现执行计划并没有按照索引来,这里其实是Oracle的一个缺陷了,
例如:DT_TIME-7<sysdate 与 DT_TIME<sysdate+7 在我们看来是一样的,但是在Oracle眼里却是不一样的,前面的表达式不会走索引,而后面的表达式就会走索引
下面的查询就不能使用JOB列上的索引,除非它是基于函数的索引:
select * from emp where UPPER(job) = 'MGR';
下面的查询使用JOB列上的索引,但是它将不会返回JOB列具有'Mgr'或'mgr'值的行:
select * from emp where job = 'MGR';
可以创建这样的索引,允许索引访问支持基于函数的列或数据。可以对列表达式UPPER(job)创建索引,而不是直接在JOB列上建立索引,如:
create index EMP$UPPER_JOB on emp(UPPER(job));
尽管基于函数的索引非常有用,但在建立它们之前必须先考虑下面一些问题:
1.能限制在这个列上使用的函数吗?如果能,能限制所有在这个列上执行的所有函数吗
2.是否有足够应付额外索引的存储空间?
3.在每列上增加的索引数量会对针对该表执行的DML语句的性能带来何种影响?
4.基于函数的索引非常有用,但在实现时必须小心。在表上创建的索引越多,INSERT、UPDATE和DELETE语句的执行就会花费越多的时间。
注意:对于优化器所使用的基于函数的索引来说,必须把初始参数QUERY _REWRITE _ ENABLED设定为TRUE。
示例:
创建索引前:select count(*) from sample where ratio(balance,limit) >.5;
Elapsed time: 20.1 minutes
创建索引: create index ratio_idx1 on sample (ratio(balance, limit));
创建索引后:select count(*) from sample where ratio(balance,limit) >.5;
Elapsed time: 7 seconds!!!
函数索引限制:
1、必须使用一个确定的函数定义基于该函数的索引,也就是说函数仅返回一个值
2、必须使用返回可重复值的函数来定义基于该函数的索引,如sysdate就不行
3、可以对基于函数的索引进行分区,但是对基于函数的全局分区索引来说,分区键不能是索引所基于的函数
4、函数必须使用圆括号来定义,即使没有参数
5、索引基于的函数不能包含聚合函数
使用建议:
1、不要轻易在字段前面加函数
2、尽量不要将字段嵌入表达式中
3、尽量减少使用函数索引,能不用就不用,因为函数索引的维护代价比普通索引高;函数索引计算值可能大于原字段值,将消耗更多的存储空间
不要在字段前增加函数
如:to_char(start_time,'yyyy.mm.dd') between '2013.06.06' and '2013.06.10'
和
start_time between to_date('2013.06.06','yyyy.mm.dd') and to_date('2013.06.10','yyyy.mm.dd')
任何时候都应该是第二种!!!
不要把字段嵌入到表达式中
如:start_time + 7 < sysdate;
和
start_time < sysdate - 7