一条Sql语句中因为含有变量,导致了其执行计划的不确定性,这时候,为保证执行计划按照我们的要求运行,最好是加上强制索引;但有时即使加了强制索引,执行计划还是没有按照我们预期的方式执行,这时候该怎么办呢?
在这里我就给大家分享一下我曾经遇到的一次这样的经历。
首先,我的语句是这样写的,在存储过程中:
select count(1) from bag_info a, out_store_info b where a.bag_id = b.bag_id and a.material_type = 'W'
and b.to_store_id = 'SP' and a.bag_id like v_Bag||'%';
其中,bag_info这个表是一个大表,有几十个millions,bag_id是主键,主键索引名为pk_bag_info。
按照正常的想法,它应该是走pk_bag_info的索引,可是在实际的运行过程中,它并没有走主键索引。我猜想是由于v_Bag这个变量的不确定性,加上与out_store_info这个表相关联,导致Oracle无法判断它应该走哪个索引。所以,我很轻易地想到给它加一个强制索引,语句改为如下:
select /*+ index(a pk_bag_info) */
试运行了一下,很好,果然走了pk_bag_info这个索引,运行非常快,以为大功告成了。
可是突然有一天半夜的时候,生产上的主管打电话给我说这个程序跑不动了。因为正好是零点刚过,这时候一般会有一些大的Job在跑,所以让他们Call DBA也看看怎么回事。
DBA仔细查看了数据库后台,Loading虽然比较高,但跟往天这个时候比,其实没有明显差别;但在Top Sql里面排名首位的正好是上面这条语句。只能猜想,当数据库Loading处于高位的时候,执行计划变得不稳定了导致的吧。没办法,只好从热腾腾的被窝里爬起来了。
既然加了强制索引还不行,试着将它改变成别外一种写法,如下:
strSql:='select /*+ index(a SYS_C0010548) */ count(1) from cqpweb.bag_info a, cqpweb.out_store_info b where a.bag_id = b.bag_id and a.material_type = ''W'' and b.to_store_id = ''SP'' and a.bag_id like :v1||''%''';
execute immediate strSql into v_Count using v_Bag;
再次运行,还真OK了。而且几个月来,再没出现被卡的现象。什么原因?期待高手作答。