Oracle优化器模式不同导致索引失效

       最近测试过程中碰到一个诡异的问题:增加相同的索引,执行相同的查询语句,在A数据库查询耗时缩短,可在B数据库查询耗时几乎不变。这让我一度怀疑B数据库有毒,然而重启大法也没能解决。最后确认问题是由于oracle优化器模式不同,导致不规范索引造成的索引失效。

       下面详细看看这个例子。

       增加索引语句如下:

CREATE INDEX idx_datetime ON my_Table(init_date,curr_date,update_time) TABLESPACE MY_IDX    

       这个语句增加了由三个字段组成的索引。相同的索引,在A数据库有效,而在B数据库无效,怀疑是数据库优化器的模式不同。

       使用以下语句查看数据库优化器模式。

Show parameter opti;

       其中,A数据库的模式是ALL_ROWS。

       B数据库的优化器模式是RULE。

       Oracle的优化器有两种,基于规则的优化器(RBO)和基于代价的优化器(CBO)。上述例子中的ALL_ROWS是基于代价的优化器CBO,RULE是基于规则的优化器RBO。

       RBO有着一套严格的使用规则,只要你按照它去写SQL语句,无论数据表中的内容怎样,也不会影响到你的“执行计划”,也就是说RBO对数据不“敏感”;它根据ORACLE指定的优先顺序规则,对指定的表进行执行计划的选择。在RBO中,SQL的写法往往会影响执行计划。上述例子中,数据库B用的是RBO优化器。我们来看看用于测试的查询语句。

1 select count(*) as count_n  
2        from my_Table  
3        where ((curr_date = 20200525 and update_time <= 153000)  
4        or (curr_date = (select max(a.init_date) from your_Table a where a.init_date < 20200525) and update_time > 153000)  
5        or (curr_date > (select max(a.init_date) from your_Table a where a.init_date < 20200525) and curr_date < 20200525))  

       在这个查询语句中,实际用于过滤my_Table表的是curr_date和update_time两个字段,而新增索引中有三个字段[init_date, curr_date, update_time],多了一个init_date字段,导致RBO模式下判定第一个字段无用,从而使整个索引失效。

       因此,对于RBO优化器模式来说,想提高这个查询的速度,有效的索引是[curr_date, update_time],修改索引后再进行查询,速度明显提高。

       而CBO优化器模式相对灵活,它会根据SQL语句生成一组可能被使用的执行计划,估算出每个执行计划的代价,并调用计划生成器(Plan Generator)生成执行计划,比较执行计划的代价,最终选择选择一个代价最小的执行计划。使用原先的三个字段作为索引,也不会有问题。

原文地址:https://www.cnblogs.com/yukifun/p/13024684.html