大数据查询时,建立的索引无效(自定义索引使用)

背景:最近在优化某些SQL,数据量也不是很大,就几百万笔数据,但是发现针对某个时间,下了条件后,查询的数据非常慢,而且不是慢的一点点,看了下COST值,居然是全表扫描,但是针对时间栏位我明明已经做了索引,但是就是不起作用。

我们知道,针对大数据量的表,如果条件中需要根据某些字段来作为查询条件查找数据,我们通常会对那些字段建立索引,通常,如果数据量大的话,oracle会以自己优化的方式,通过我们建立的索引来查找数据,这样会使查询速度变快很多。
但是如果某些条件是经过处理的,即使用了函数,那么索引将立即失效,比如说“select * from tableName where substr(cloumnName,3,1)= ‘test’ ”,此时,如果为cloumnName设立了索引,那么实际上,如果使用切割字符串后的结果作为条件,那么oracle永远都不会使用这个索引的。

看下面的例子
可恨的德国佬在建表的时候,非要把简单的年月日时分秒记成2个栏位bearb_date和bearb_time两个栏位,前一个字段是年月日,即yyyy/mm/dd的date类型,后一个字段是那天的时间距离那天0点的秒数,是number类型,说白了也就是那天的时分秒。

所以当在以时间范围查询的时候,必须做一个转换,并且oracle还没有现成的转换函数,只能自己写一个函数,即下面的get_datetime(date,time)函数。

1.为此表的这2个字段建立索引
大数据查询时,建立的索引无效(自定义索引使用)_第1张图片
2.经查看,索引的建立并没有起到作用,还是走全表查
大数据查询时,建立的索引无效(自定义索引使用)_第2张图片
3.为此表建立自定义函数索引**(这里自定义函数存在一个坑,需要注意下,看文章最后)**
在这里插入图片描述
4.此时再查一下结果集,我们看下COST值,该表已经使用了我们建立的索引查询结果了
大数据查询时,建立的索引无效(自定义索引使用)_第3张图片
5.结论:如果针对大数据量查询,如果用到函数作为条件,不管是自定义函数还是Orace自带的函数,请把该函数写到索引中,否则直接用字段作为索引,是不会起到作用的。


然后我再来说下自定义函数的坑:

以下是其他博主写的测试过程,我就不废话了,原文地址:
http://blog.sina.com.cn/s/blog_6ff05a2c0100n2qo.html
内容如下:

我们平时在SQL语句的WHERE条件中使用函数是很常见的事情,考虑一下下面两个SQL在执行机制上有什么区别:

  1. SELECT * FROM T WHERE col1 = UPPER(‘hello’);
  2. SELECT * FROM T WHERE col1 = DBMS_RANDOM.VALUE(1,100);

UPPER(‘hello’)经过处理后会变成’HELLO’,它相当于一个常量,因此第1个SQL类似于: SELECT * FROM T
WHERE col1 = ‘HELLO’;
而第2个SQL由于DBMS_RANDOM.VALUE(1,100)是不确定的,因此不能进行处理。这就导致T表有多少行,DBMS_RANDOM.VALUE这个函数就要执行多少次。而第1个SQL其实只执行了很少次数的UPPER函数,与表T的行数无关。
如果我们想自己写一个函数SQUARE,实现平方的功能,那么在下面的SQL中,SQUARE函数会执行多少次呢? SELECT * FROM T
WHERE col = SQUARE(10); 我们可以通过实验来测试它,实验的大致方法是:
1.创建一个包,包里面定义一个NUMBER类型的变量,初始值设为0。
2.在我们自己定义的函数中增加一个将全局变量+1的赋值操作,这样每调用一次该函数,全局变量就会增加1。
3.最后输出全局变量的值,就是该函数被调用过的次数。当然每次测试前要将全局变量清零。

说到这里我要提一个oracle函数的属性,就是deterministic。它表示一个函数在输入不变的情况下输出是否确定,像oracle的内置函数UPPER,TRUNC等都是deterministic函数,而像DBMS_RANDOM.VALUE就不是deterministic函数,因为同样的输入不一定会导致同样的输出。
如果我们在定义SQUARE函数时没有加deterministic属性,那么经过我的测试,SELECT * FROM T WHERE col
= SQUARE(10); 这个SQL会执行ROWNUMBER次SQUARE函数,也就是如果表T有100行,那就执行100次。 如果我们在定义SQUARE函数时加上了deterministic属性,那么经过我的测试,SELECT * FROM T WHERE col
= SQUARE(10); 这个SQL只会执行2次SQUARE函数,而不管表T有多少行。 因此给出结论:当我们自己创建函数时,如果能够确定该函数是确定的,那就一定要加上deterministic属性,这样在where条件中使用该函数会提高一大截性能!否则,你写的函数将来被多少人使用就是害了多少人!

最后我给出结论:
1.oracle对于非deterministic函数,无法建立索引,重要的事情说三遍,不能建立索引,不能建立索引,不能建立索引!
2.针对oracle的内置函数基本上都是deterministic函数,因此可以直接对该函数建立索引。
3.如果是自定义函数,如果能够确定该函数是确定的,那就一定要加上deterministic属性,不仅会使函数性能大大提高,更重要的是,能对该函数建立索引!

如图:
大数据查询时,建立的索引无效(自定义索引使用)_第4张图片

你可能感兴趣的:(oracle,索引失效,自定义函数,oracle,数据库)