0
点赞
收藏
分享

微信扫一扫

Oracle中B-tree索引的访问方法(十三)-- 对B-tree索引认识的几个常见误区

对B-tree索引认识的几个常见误区

误区1:除非新插入的索引值与被删除的值完全一样,否则索引中被删除条目所占的空间不会被重用。

这是我们常听到的,关于索引的第一个误解。我们还是通过实验来证明这个说法是错误的:

Oracle中B-tree索引的访问方法(十三)-- 对B-tree索引认识的几个常见误区_索引


图 155

如上图所示,我们创建了一个测试表和测试索引,其结构与我们之前做的实验是类似的。故这里不再赘述。

查看该索引的树形结构:

Oracle中B-tree索引的访问方法(十三)-- 对B-tree索引认识的几个常见误区_误区_02


图 156

如上图所示,该索引有3层。我们的测试在将第2个叶子块(leaf: 0x1844bbd 25447357 (0: nrow: 13 rrow: 13))上进行。我们会先将该叶子块中的记录,每间隔一个,删除掉一个,然后再向其中插入同样数量的记录,但新插入的记录值与删除的记录值并不一样。看看叶子块上那些被删除的空间,是否会被重用。

首先,我们DUMP出第2个叶子块上的数据,确认其中的存储的值:

Oracle中B-tree索引的访问方法(十三)-- 对B-tree索引认识的几个常见误区_b-tree_03


图 157

如上图所示,我们可以看到该叶子块中的13个索引条目,最小值是’070’结尾的字符串,最大值是’130’结尾的字符串。由于我们构造数据时,用的是rownum*5,所以,剩余11个值,即’075’,’080’,’085’,’090’,’095’,’100’,’105’,’110’,’115’,’120’,’125’虽然未在这里显示,但大家也能推测得出来。

我们隔一个删除一个,即将前面提及的,最后一位字符为’5’的6条记录删除。如下所示:

Oracle中B-tree索引的访问方法(十三)-- 对B-tree索引认识的几个常见误区_b-tree_04


图 158

然后,我们再插入6条其它值,但也是在’070’和’130’之间的值。如下所示:

Oracle中B-tree索引的访问方法(十三)-- 对B-tree索引认识的几个常见误区_b-tree_05


图 159

现在,我们再来查该索引的树形结构,看看与原来相比,是否有了变化?

Oracle中B-tree索引的访问方法(十三)-- 对B-tree索引认识的几个常见误区_误区_06


图 160

如上图所示,经与原树形结构相比较,并无变化。如果原来叶子块中被删除的空间不能被重用,那么首先第2个叶子块中的rrow的值会有变化;其次,由于原叶子块中原来只有1327个字节的可用空间,显然是不可能放下6个索引条目的。所以,如果不能重用空间,这些新插入的值会导致叶子块上的分裂,至少会有一部索引条目写到新块上。但我们并没有看到叶子块的总量有增加,也没有看到相邻叶子块上有索引条目数量上的变化。

所以,被删除的索引条目所占用的空间,是可以被重用的。但重用的前提是这些新值仍归属于该叶子块。

误区2:单调递增的索引值,删除的旧值索引条目所占用的空间无法重用。

这个误解,来自于误区1。在误区1中,我们最后的结论是“被删除的索引条目所占用的空是,是可以被重用的。但重用的前提是这些新值仍归属于该叶子块。” 显然,如果新插入的值,不在原删除叶子块的值范围内,那么索引空间也就不会被重用了。因此,对于单调递增的索引,由于新插入的值总是大于旧值,即新值将位于索引的最右侧的叶子块上。所以,删除的旧值所占用的索引空间,也就无法被重用了。

这个认知不能说错,应该说至少对了一多半。其前提条件,是原叶子块中,总是有未被删除的索引条目,即被删除了索引条目的叶子块,永远不会成为空闲块。如果某个索引块中的全部索引条目都被删除了,那么这个块会成为空闲块,并会被再次使用。

我们继续沿用误区1中的实验样例,将第2个叶子块上的全部索引条目删除:

Oracle中B-tree索引的访问方法(十三)-- 对B-tree索引认识的几个常见误区_b-tree_07


图 161

然后我们查看此时索引的树形结构信息:

Oracle中B-tree索引的访问方法(十三)-- 对B-tree索引认识的几个常见误区_索引_08


图 162

如上所示,我们可以看到第2个叶子块(leaf: 0x1844bbd 25447357)中的rrow已经变为了0。

接下来,我们向该索引的最大值之上,再插入15行记录,以确保会需要使用新的索引块。如下所示:

Oracle中B-tree索引的访问方法(十三)-- 对B-tree索引认识的几个常见误区_误区_09


图 163

此时查看索引的树形结构信息:

Oracle中B-tree索引的访问方法(十三)-- 对B-tree索引认识的几个常见误区_索引_10


图 164

如上所示,我们发现原来第2个叶子块,rrow为0的那个叶子块从原来的位置消失了。而相同dba的索引块(leaf: 0x1844bbd 25447357),在最后一个叶子块的位置中出现了。

综上,通过这个实验,我们也证明了“单调递增的索引值,删除的旧值索引条目所占用的空间无法重用。”这个认识,也是不完全正确的。

误区3:索引的高度越低越好。

从前面对B-tree索引的访问方法的观察中,我们可以发现,索引唯一扫描,索引范围扫描,索引全扫描都要经历根块,分支块最终访问到叶子块。如果分支块层少,则可以减少所需访问的数据块。比如,对于一个3层的索引,访问到叶子块前,要访问2个索引块(根块,分支块),对于一个4层的索引,则需要访问3个索引块(根块,2个分支块);而索引快速全扫描则是访问全部索引块。虽然不是说索引高度高的,其包含的索引块就必然越多。但对于同样定义的索引,高度越高,索引块越多,显然,就算不是索引的唯一扫描或范围扫描,而是进行索引快速全扫,也是需要访问更多的数据块的。而索引跳跃扫描,也是需要访问多次分支块和叶子块。索引高度的高和低,对索引跳扫可能的访问影响的讨论会比较复杂。但是,总体上来说,索引块越多,索引跳跃扫描的成本可能越高。
如上所述,仅从访问索引块的数量来看,确实索引高度越低,同样条件下,需要访问的索引块会更少,需要的资源开销也会更小。但是,对于一个非静态的表,其上的数据会有所变化,这时,反映到相应的索引上,就可能会发生索引的分裂。而索引的分裂是相对资源开销较大,而且通常只能是串行进行的操作(即对于同一个索引,在同一时刻,只能有一个会话在进行索引分裂),这时,就可能导致数据库出现严重的事务锁争用现象。因此,保持索引适当的高度,在访问效率和减少索引分裂之间要达到一个平衡才是最好的,而不是索引高度越低越好。

误区4:为了维持有效率的索引访问,需要定期重建索引。

这个认识,我猜测可能与前面提到的三个误区相关。因为担心索引中出现大量无法重用的空间或碎片,同时,又希望有更低的索引高度,而保持更佳的访问效率。所以,希望对经常发生DML操作的表上的索引,定期进行重建索引的操作。以回收未用的空间,降低索引的高度。但如前所述,对于大多数情况,索引中未用的空间会被重新利用,而片面强调降低索引高度,可能会在其它方面带来损害。因此,为了维持有效的索引访问,而定期重建索引,也是不完全,或者说大多数的时候,都是错误的。

举报

相关推荐

0 条评论