Oracle优化器模式不同导致索引失效
Posted Akira_Z
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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)生成执行计划,比较执行计划的代价,最终选择选择一个代价最小的执行计划。使用原先的三个字段作为索引,也不会有问题。
以上是关于Oracle优化器模式不同导致索引失效的主要内容,如果未能解决你的问题,请参考以下文章