目前,oracle采用的是CBR优化器,所以在有些时候,机器会按照自己的意愿去执行sql,当然oracle是根据本身的一些信息来做决定的,比如:统计信息。但有些时候,机器并不一定会按照我们预想的那样去执行。
今天就遇到这样的一个问题,在查看某一段时间内的出运明细时,执行时间较长。sql如下:
select * from C1.T_DECLAREDETAIL t1 where t1.commitdate >= to_date('2013-01-01', 'YYYY-MM-DD') and t1.commitdate < to_date('2013-06-30', 'YYYY-MM-DD') + 1
通过查看执行计划,发现进行了全表扫描。因为commitdate字段上有索引,我本以为会走索引的。
很明显,是做了全表扫描。
做了个实验,如果用commitdate等于某一个日期的话,会走索引。通过这个实验,我怀疑是因为oracle自作主张的认为这段时间里的数据量占整个数据量的10%以上,选择性不高,所以做了全盘扫描。为了验证我的假设,我把范围进行了缩小,结果发现很明显的走了索引:
测试到这里,我也没有更好的办法了,只好给脚本加上hint了。在一般情况下,最好是不要通过hint来处理。修改后的脚本如下:
select /*+ INDEX (t1 IND_T_DECLAREDETAIL_COMMIT)*/ *
from C1.T_DECLAREDETAIL t1
where t1.commitdate >= to_date('2013-01-01', 'YYYY-MM-DD')
and t1.commitdate < to_date('2013-06-30', 'YYYY-MM-DD') + 1
执行计划如下:
从执行计划里能看出,这个脚本是走了执行计划的。而且实践也证明,这下修改后,执行时间也确实缩短了。