设为首页 加入收藏

TOP

Oracle优化器的基础知识(二)
2017-02-15 08:15:18 】 浏览:609
Tags:Oracle 优化 基础知识
,那么当Oracle知道待访问的数据行所在的ROWID后,自然就可以根据该RWOID去直接访问对应表的相关数据行,这就是ROWID扫描的含义。


从严格意义上来说,Oracle中的ROWID扫描有两层含义:一种是根据用户在SQL语句中输入的ROWID的值去直接访问对应的数据行记录;另外一种方法是先去访问相关的索引,然后根据访问索引后得到的ROWID再回表去访问对应的数据行。


对Oracle中的堆表而言,我们可以通过Oracle内置的ROWID伪列得到对应行记录所在的ROWID值,然后还可以通过DBMS_ROWID包中的相关方法将ROWID伪列的值翻译成对应数据行的实际物理存储地址。


3.2 访问索引的方法


这里提到的索引是指最常用的B*Tree索引



Oracle数据库的的B*Tree索引就好像一棵倒长的树,它包含两种类型的数据块,一种是索引分支块,另一种是索引叶子块。


索引分支块包含指向相应索引分支块/叶子块的指针和索引键值列(这里的指针是指相关分支块/叶子块的块地址RDBA。每个索引分支块都会有两种类型的指针,一种是lmc,另一种是索引分支块的索引行记录所记录的指针。lmc是Left Most Child的缩写,每个索引分支块都只有一个lmc,这个lmc指向的分支块/叶子块中的所有索引键值列中的最大值一定小于该lmc所在索引分支块的所有索引键值列中的最小值;而索引分支块的索引行记录所记录的指针所指向的分支块/叶子块的所有索引键值列中的最小值一定大于或等于该行记录的索引键值列的值)。这个索引列值不一定就是完整的被索引键值,它可能只是被索引键值的前缀,只要Oracle能通过这些前缀区分相应的索引分支块/叶子块就行,这样Oracle就能够既节省分支块的存储空间,又可以快速定位其下层的索引分支块/叶子块。索引分支块最上层的那个块就是所谓的索引根节点。在Oracle里访问B*Tree索引的操作都必须从根节点开始,即都会经历一个从根节点到分支块再到叶子块的过程。


索引叶子块包含被索引键值和用于定位该索引键值所在的数据行在表中实际物理存储位置的ROWID。对于唯一性的B*Tree索引而言,ROWID是存储在索引行的行头,所以此时Oracle并不需要额外礁该ROWID的长度。而对于非唯一性的B*Tree索引而言,ROWID被当作额外的列与被索引的键值列一起存储,所以此时Oracle既要存储ROWID,同时又要存储其长度,这意味着在同等条件下,唯一性B*Tree索引要比非唯一性B*Tree索引节省索引叶子块的存储空间。对于非唯一性索引而言,B*Tree索引的有序性体现在Oralce会按照被索引键值和相应的ROWID来联合排序。Oralce里的索引叶子块是左右互联的,即相当于有一个双向指针链表把这些索引叶子块互相连接在了一起。


3.2.1 索引唯一性扫描


索引唯一性扫描(INDEX UNIQUE SCAN)是针对唯一性索引(UNIQUE INDEX)的扫描,它仅仅适用于where条件里等值查询的目标SQL。因为扫描的对象是唯一性索引,所以索引唯一性扫描的结果至多只会返回一条记录。


3.2.2 索引范围扫描


索引范围扫描(INDEX RANGE SCAN)适用于所有类型的B*Tree索引,当扫描的对象是唯一性索引时,此时目标SQL的where条件一定是范围查询(谓词条件为BETWEEN、<、>等);当扫描的对象是非唯一性索引时,对目标SQL的where条件没有限制(可以是等值查询,也可以是范围查询)。索引范围扫描的结果可能会返回多条记录,其实这就是索引范围扫描中的“范围”二字的本质含义。


在同等条件下,当目标索引的索引行的数量大于1时,索引扫描范围所耗费的逻辑读至少会比生意人索引唯一性扫描的逻辑读多1。因为扫描结果可能会返回多条记录,又因为目标索引的索引行数量大于1,Oracle为了确定索引范围扫描的扫描终点,就不得不去多次访问相关的叶子块。


3.2.3 索引全扫描


索引全扫描(INDEX FULL SCAN)适用于所有类型的B*Tree索引(包括唯一性索引和非唯一性索引)。所谓的“索引全扫描”,就是指要扫描目标索引所有叶子块的所有索引行。这里需要注意的是,索引全扫描需要扫描目标索引的所有叶子块,但并不意味着需要扫描该索引的所有分支块。在默认情况下,Oracle在做索引全扫描时只需通过访问必要的分支块定位到位置该索引最左边的叶子块的第一行索引行,就可以利用该索引叶子块之间的双向指针链表,从左至右依次顺序扫描该索引所有叶子块的所有索引行了。由于索引是有序的,所以索引全扫描的执行结果也是有序的,并且是按照索引的索引键值列来排序,这也意味着走索引全扫描能够既达到排序的效果,又同时避免了对该索引的索引键值列的真正排序操作。


默认情况下,索引全扫描的扫描结果的有序性就决定了索引全扫描是不能够并行执行的,并且通常情况下索引全扫描使用的是单块读。


通常情况下,索引全扫描是不需要回表的,所以索引全扫描适用于目标SQL的查询全部是目标索引的索引键值列的情形。我们知道,对于Oracle数据库的B*Tree索引而言,当所有索引键值列全为NULL值时不入索引,这意味着Oracle中能做索引全扫描的前提条件是目标索引至少有一个索引键值列的属性是NOT NULL。这很显然,如果目标索引的所有索引键值列的属性均为允许NULL值,此时如果还走索引全扫描,就会漏掉目标表中那些索引值列均为NULL的记录,即此时走索引全扫描的结果就不准了!Oracle不允许这种事情发生。


3.2.4 索引快速全扫描


索引快速全扫描(INDEX FAST FULL SCAN)和索引全扫描极为类似,它也适用于所有类型的B*Tree索引。和索引全扫描一样,索引快速全扫描也需要扫描目标索引所有叶子块的所有索引行。


索引快速全扫描与索引全扫描相比有如下三点区别:


1)索引快速全扫描只适用于CBO。


2)索引快速全扫描可以使用多块读,也可以并行执行。


3)索引快速全扫描的执行结果不一定是有序的。这是因为索引快速全扫描时Orace是根据索引行在磁盘上的物理存储顺序来扫描,而不是根据索引行的逻辑顺序来扫描的,所以扫描结果才不一定有序(对于单个索引叶子块的索引行而言,其物理存储顺序和逻辑存储顺序一致;但对于物理存储位置相邻的索引叶子块而言,块与块之间索引行的物理存储顺序则不一定在逻辑上有序)。


3.2.5 索引跳跃式扫描


索引跳跃式扫描(INDEX SKIP SCAN)适用于所有类型的复合B*Tree索引,它使那些在where条件中没有对目标索引的前导列指定查询条件,但同时又对该索引的非前导列指定了查询条件的目标SQL依然可以使用上该索引,这就像是在扫描该索引时跳过了它的前导列,直接从该索引的非前导到开始扫描一样(实际执行过程并非如此),这民是索引跳跃式扫描中“跳跃”(SKIP)一词的含义。


Oracle中的索引跳跃式扫描仅仅适用于那些目标索引前导导列的distinct值数量较少,后续非前导列的可选择性又非常好的情形,因为索引跳跃式扫描的执行效率一定会随着目标索引前导列的distinct值数量的递增而递减。


首页 上一页 1 2 下一页 尾页 2/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇MySQL 5.7.16 修改密码提示 ERROR.. 下一篇MySQL5.6.18解压包版在RHEL6.7上..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目