Oracle中B-tree索引的访问方法(六)-- 索引全扫描
  IE5LYMWlmdvL 2023年11月14日 27 0

索引的访问方法之全扫描

索引全扫描(INDEX FULL SCAN)虽然与索引快速全扫描只差了“快速”(FAST),但其访问方法却与后者有明显差别:其一,索引全扫描是单块读,而索引快速全扫描是多块读。其二,索引全扫描是按叶子块的逻辑顺序,依序读取的,所以,它可以保证读取的值是有序的。而索引快速全扫描不能保证。第三,索引全扫描会沿着索引树形结构中定位最左侧(或最右侧)叶子块的路径,访问相关的索引根块和分支块,然后从该最左侧(或最右侧)叶子块开始,沿着叶子块中的双向链表,依序访问全部的叶子块。因此,索引全扫描只会访问部分分支块。

下面,我们仍然沿用前面创建的表和索引,来观察索引全扫描的行为。

由于在我们的样例表和索引中,索引的大小已经接近表的大小,同时,又由于记录数较小,所以,从成本上评估时,索引快速全扫后再排序的代价,总是小于索引全扫的代价。这就导致很难模拟出索引全扫描的行为。因为,我们尝试修改索引的统计信息,将叶子块数量修改为1,使其在评估成本时,对索引的全扫描的成本可以小于索引快速全扫描的成本,进而可以走了索引全扫描的访问方法。

修改索引中有关叶子块数量的统计信息:

Oracle中B-tree索引的访问方法(六)-- 索引全扫描_索引


图 53

然后,我们执行以下查询,构造出索引全扫描的行为:

Oracle中B-tree索引的访问方法(六)-- 索引全扫描_b-tree_02


图 54

但在我们使用10200 event跟踪上述SQL的执行过程前,我们需要在sqlplus中设置系统变量arraysize。其默认值为15,最大值为5000。表示读取一次数据块,最多返回给用户的行的数量。假设某个叶子块中有30个索引条目,当arraysize为15时,需要分两次返回给用户,这就会对该叶子块访问2次。所以,我们为了让跟踪结果数据更容易理解,我们将arraysize设置为500,已经大于表中的行数了,也一定大于任一叶子块中的索引条目数。如下图所示:

Oracle中B-tree索引的访问方法(六)-- 索引全扫描_oracle_03


图 55

此时,使用10200 event跟踪得到的结果如下图所示:

Oracle中B-tree索引的访问方法(六)-- 索引全扫描_oracle_04


图 56

为方便参照和理解,我们将该索引的树形结构信息展示如下:

Oracle中B-tree索引的访问方法(六)-- 索引全扫描_oracle_05


图 57

两相参照,我们可以看到,最先读取的是根块(dba: 0x1801e43),然后是根块下位于最左侧的分支块(dba: 0x1801e56),再然后,是该分支块下最左侧的叶子块(dba: 0x1801e44),此后,沿着当前叶子块中记录的后一个叶子块的指针(kdxlenxt,可参考前述叶子块结构部分的介绍),依序访问所有的叶子块。

这里,我们注意到最左侧的叶子块,也是第一个被访问到的叶子块(dba:0x1801e44)被访问了两次,其原因,在索引范围扫描部门已经做了说明,这里不再赘述。

将前述观察到的访问次序,画成示意图,如下图所示:

Oracle中B-tree索引的访问方法(六)-- 索引全扫描_全扫描_06


图 58在索引全扫描的访问方法中,还有一个特殊的访问方法:INDEX FULL SCAN (MIN/MAX)。该访问方法,是利用叶子块中的索引条目值是有序的特点,来快速定位最小或最大值的方法。由于叶子块中的索引条目值是有序的,所以,索引中最小的值一定在最左侧的叶子块中,而索引中最大的值,也一定在最右侧的叶子块中。所以,当我们执行类似如下的查询时,就会走出INDEX FULL SCAN (MIN/MAX)的访问方法,如下图所示:

Oracle中B-tree索引的访问方法(六)-- 索引全扫描_全扫描_07


图 59

使用10200 event跟踪的结果如下:

Oracle中B-tree索引的访问方法(六)-- 索引全扫描_oracle_08


图 60

如上所示,其访问索引块的次序正是按照根块->最右侧的分支块->最右侧的叶子块的方法来进行的。因此,正常情况下,利用索引查找索引列上的最小(或最大)值,会是非常高效的。但是,有两点需要注意:

1、 当在一个SELECT子句中,同时获取最小和最大值时,并不能让数据库自动对索引访问两次,一次访问从最左侧的叶子块(找最小值)开始,一次访问从最右侧的叶子块(找最大值)开始。而是通过全表扫描的方式来同时获取最小值和最大值。如下例所示:

Oracle中B-tree索引的访问方法(六)-- 索引全扫描_索引_09


图 61

这时,我们需要对目标SQL进行改写为如下等价SQL,就可以利用上索引,并使用INDEX FULL SCAN (MIN/MAX)这种高效的方法来访问。如下所示:

Oracle中B-tree索引的访问方法(六)-- 索引全扫描_索引_10


图 62

2、 尽管INDEX FULL SCAN (MIN/MAX)的访问很高效,通常只需要沿着访问最左侧(或最右侧)叶子块的路径,访问少量几个索引块,即可以得到相应的最小值(或最大值)。但是,如果索引中最左侧(或最右侧)的叶子块及其后续(或前置)多个叶子块中的值均已被删除,而这些叶子块又没有被回收时,就可能导致在最左侧(或最右侧)的叶子块中并没有有效的索引值,需要继续沿着叶子块上的双向链接向后(或向前)访问下一个叶子块。当出现这种位于前端(或后端)的空块较多时,就会导致相关SQL的性能偏低。这时,就需要对索引重建或回收碎片空间了。

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月14日 0

暂无评论

推荐阅读
  xaeiTka4h8LY   2024年05月31日   37   0   0 MySQL索引
IE5LYMWlmdvL