深入内核:CBO对于Cost值相同索引的选择
创始人
2025-01-27 22:20:34
0次

 

[[163836]]

  崔华,网名 dbsnake

  Oracle ACE Director,ACOUG 核心专家

  编辑手记:感谢崔华授权我们独家转载其精品文章,也欢迎大家向“Oracle”社区投稿。

  这里我们稍微讨论一下CBO对于Cost值相同的索引的选择,可能会有朋友认为在同样Cost的情况下,Oracle会按照索引名的字母顺序来选择索引,实际上并不完全是这样,CBO对于Cost值相同的索引的选择和Oracle的版本有关。

  原理说明

  MOS上文章“Handling of equally ranked (RBO) or costed (CBO) indexes [ID 73167.1]”明确指出——When the CBO detects 2 indexes that cost the same, it makes the decision based on the following:

  (up to release 9.2.06) indexes ascii name so that index ‘AAA’ would be chosen over index ‘ZZZ’. See Bug 644757

  (starting with 9.2.0.7 and in 10gR1) bigger NDK for fully matched indexes (not for fast full scans). See Bug 2720661

  (in 10gR2 and above) index with lower number of leaf blocks. See Bug 6734618

  这意味着对于Oracle 10gR2及其以上的版本,CBO对于Cost值相同的索引的选择实际上会这样:

  1-如果Cost值相同的索引的叶子块数量不同,则Oracle会选择叶子块数量较少的那个索引;

  2-如果Cost值相同的索引的叶子块数量相同,则Oracle会选择索引名的字母顺序在前面的那个索引。

  测试验证

  这个非常容易验证,我们来看一个实例。在一个11.2.0.3的环境中创建一个测试表T1:

  Connected to Oracle Database 11g Enterprise Edition Release 11.2.0.3.0

  Connected as nbs

  SQL> create table t1 as select * from dba_objects;

  Table created

  对T1增加一列object_id_1,并将其值修改成和列object_id的值一致:

  SQL> alter table t1 add (object_id_1 number);

  Table altered

  SQL> update t1 set object_id_1=object_id;

  83293 rows updated

  SQL> commit;

  Commit complete

  分别在列object_id和列object_id_1上创建名为a_idx_t1和b_idx_t1的B树索引:

  SQL> create index a_idx_t1 on t1(object_id);

  Index created

  SQL> create index b_idx_t1 on t1(object_id_1);

  Index created

  对表T1收集一下统计信息:

  SQL> exec dbms_stats.gather_table_stats(ownname => ‘NBS’, tabname => ‘T1’, estimate_percent => 100, cascade => TRUE, no_invalidate => false);

  PL/SQL procedure successfully completed

  此时索引a_idx_t1和b_idx_t1的统计信息显然是完全一致的(这意味着走这两个索引的同类型执行计划的Cost值会相同),从如下查询结果中我们可以看到,它们的叶子块的数量均为185:

  SQL> select index_name,leaf_blocks from dba_indexes where table_owner=’NBS’ and table_name=’T1′;

  INDEX_NAMELEAF_BLOCKS

  —————————— ———–

  A_IDX_T1185

  B_IDX_T1 185

  在当前情形下,如果我们执行目标SQL:

  “select * from t1 where object_id=1000 and object_id_1=1000”

  显然此时Oracle既可以走索引a_idx_t1,也可以走索引b_idx_t1。

  从如下查询结果中我们可以看到,此时Oracle选择了走索引a_idx_t1:

  SQL> set autotrace traceonly explain

 

  SQL> select * from t1 where object_id=1000 and object_id_1=1000;

  这就验证了我们之前提到的结论——对于Oracle 10gR2及其以上的版本,如果Cost值相同的索引的叶子块数量相同,则Oracle会选择索引名的字母顺序在前面的那个索引。

  现在我们把索引b_idx_t1的叶子块数量从之前的185改为现在的184:

  SQL> exec dbms_stats.set_index_stats(ownname => ‘NBS’, indname => ‘B_IDX_T1’, numlblks => 184);

  PL/SQL procedure successfully completed

  从如下查询结果中我们可以看到,上述改动生效了:

  SQL> select index_name,leaf_blocks from dba_indexes where table_owner=’NBS’ and table_name=’T1′;

  INDEX_NAMELEAF_BLOCKS

  —————————— ———–

  A_IDX_T1185

  B_IDX_T1184

  然后我们再次执行上述目标SQL:

 

  SQL> select * from t1 where object_id=1000 and object_id_1=1000;

  从上述显示内容中我们可以看到,上述SQL的执行计划从之前的走对索引a_idx_t1的索引范围扫描变为了现在的走对索引b_idx_t1的索引范围扫描,这就验证了我们之前提到的结论:对于Oracle 10gR2及其以上的版本,如果Cost值相同的索引的叶子块数量不同,则Oracle会选择叶子块数量较少的那个索引。

 

相关内容

热门资讯

PHP新手之PHP入门 PHP是一种易于学习和使用的服务器端脚本语言。只需要很少的编程知识你就能使用PHP建立一个真正交互的...
网络中立的未来 网络中立性是什... 《牛津词典》中对“网络中立”的解释是“电信运营商应秉持的一种原则,即不考虑来源地提供所有内容和应用的...
各种千兆交换机的数据接口类型详... 千兆交换机有很多值得学习的地方,这里我们主要介绍各种千兆交换机的数据接口类型,作为局域网的主要连接设...
粉嫩如何诠释霸道 东芝M805... “霸道粉”是个什么玩意东芝M805拿过来的时候,笔者扑哧笑了,不是笑这款笔记本,而是笑这款产品的颜色...
如何利用交换机和端口设置来管理... 在网络管理中,总是有些人让管理员头疼。下面我们就将介绍一下一个网管员利用交换机以及端口设置等来进行D...
什么是大数据安全 什么是大数据... 在《为什么需要大数据安全分析》一文中,我们已经阐述了一个重要观点,即:安全要素信息呈现出大数据的特征...
全面诠释网络负载均衡 负载均衡的出现大大缓解了服务器的压力,更是有效的利用了资源,提高了效率。那么我们现在来说一下网络负载...
如何允许远程连接到MySQL数... [[277004]]【51CTO.com快译】默认情况下,MySQL服务器仅侦听来自localhos...
只需三步,让你掌握阿尔法路由器... 请参照以下阿尔法路由器设置方法,通过浏览器进入及设置宽带路由器。经过这三个步骤的设置,基本上能够熟悉...
30分钟搞定iOS自定义相机 最近公司的项目中用到了相机,由于不用系统的相机,UI给的相机切图,必须自定义才可以。就花时间简单研究...