关于索引的内部信息(r3笔记第83天)

作者: admin 分类: 公众号存档            0 次浏览 发布时间: 2014-12-13 23:43

公众号:杨建荣的学习笔记 · 作者:r3笔记第83天 · 发布:2014-12-13 23:43:27 · 原文链接

在oracle中对于索引的存储都是采用B树索引来实现。B树索引是比较成熟的一种数据存储结构,在很多的软件中都有大量的应用,oracle中也不例外。
因为B树索引是树形结构。存储的时候也是带枝带叶的。简单来说,索引就像文章里的目录,字典中的词条检索项。
索引分为根节点,分支节点和叶子节点。这种结构对应生活中的树来说明就很形象了。根节点就如同树干,只有一个树干。树干中有很多的树枝,就如分支节点,每个树枝中还会有一些叶子,就如叶子节点。比如我们要存储的数据,把它分为3个分支,那么在根节点中就假设有三个键值 0,500,1000分别代表分支节点中的最小键值。然后在分支节点中就分别对(0,500),(500,100),(1000,1000+)的数据做进一步的细分,比如对于(0,500),我们可以细分为0,200,400,那么就对应(0,200), (200,400),(400,500),这样的话对于(0,500)就存在3个分支节点,然后我们在叶子节点中对分支节点的键值再做一层细分,比如(0,200),我们可以细分为0,50,150.
最后叶子节点的数据就和表的数据行就会有一个最终的映射。数据查找的时候也会高效。
但是话说过来,不管根节点,叶子节点,分支节点,在数据库中都得存储在数据块中。那么一个数据库块中就可能存储多个分支节点或者多个叶子节点。相当于把这些节点的数据都打包了,只是通过逻辑能够很快定位到某个叶子节点在哪个数据块中。
对于索引的一些细节信息,我们可以通过index_stats来查看。这个时候就需要使用analyze这个命令了,在user_indexes中也有一些基本的索引存储信息,这个时候可以使用dbms_stats来分析。

我们来简单的通过实例来说明。
我们创建一个表。
create table index_test as select *from user_objects;
然后创建一个索引。
create index inx_test on index_test(object_id);
使用analyze来分析索引的信息,尽管在新版本中我们建议使用dbms_stats来替代analyze,但是analyze validate structure这个功能时analyze独有的,dbms_stats在这方面还不能完全替代analyze.
analyze index inx_test validate structure;
select height,blocks,br_blks,lf_blks,lf_rows,del_lf_rows from index_stats; –高度 索引总块数 枝干块数 叶子块数 叶子内行数 叶子中被删除的行数
HEIGHT BLOCKS BR_BLKS LF_BLKS LF_ROWS DEL_LF_ROWS
———- ———- ———- ———- ———- ———–
1 8 0 1 73 0
可以看到,索引的高度是1,目前分支节点占有一个数据块,叶子节点占用一个数据块,叶子节点对应的数据行数有73行。
这个时候有一个奇怪的现象是表Index_test中有74条数据,但是为什么73行呢。

SQL> select count(*)from index_test;

COUNT(*)
———-
74

SQL> select count(*)from index_test where object_id is null;

COUNT(*)
———-
1
因为我们存在一条记录中object_id位空值了,所以没有作为索引列。
我们来随机抽取几条数据作为后续的dml操作基础。
select *from (select object_id from index_test order by dbms_random.value()) where rownum<5;
OBJECT_ID
———-
15287
22180
22295
14019

我们就选择第一条记录。做一个update操作。
update index_test set object_id=11111 where object_id=15287;
commit;
analyze index inx_test validate structure;–再次分析索引
select height,blocks,br_blks,lf_blks,lf_rows,del_lf_rows from index_stats;
HEIGHT BLOCKS BR_BLKS LF_BLKS LF_ROWS DEL_LF_ROWS
———- ———- ———- ———- ———- ———–
1 8 0 1 74 1
可以很清晰的看到叶子内行数从73变为74,然后 叶子中被删除的行数 也从0变为1.
这是因为update也是一个delete+insert的操作,新增加的一行是object_id=15287被删除时留下的。
我们来尝试一个Insert操作。
insert into index_test select *from index_test;
commit;
analyze index inx_test validate structure; –再次分析索引
select height,blocks,br_blks,lf_blks,lf_rows,del_lf_rows from index_stats;
HEIGHT BLOCKS BR_BLKS LF_BLKS LF_ROWS DEL_LF_ROWS
———- ———- ———- ———- ———- ———–
1 8 0 1 146 0
这个时候叶子内行数从74变为146. 可以这么理解73*2=146. 因为表中的非null数据有73行,所以再次插入的时候对应的叶子内行数就是73*2=146.

我们插入较多的数据来看看叶子节点的存储情况。
insert into index_test select *from index_test;
/
commit; –插入了两次
analyze index inx_test validate structure; –再次分析索引
select height,blocks,br_blks,lf_blks,lf_rows,del_lf_rows from index_stats;
HEIGHT BLOCKS BR_BLKS LF_BLKS LF_ROWS DEL_LF_ROWS
———- ———- ———- ———- ———- ———–
2 8 1 2 584 0
可以看到叶子内行数变化很大,同时叶子节点块变为了2个。
如果再逐渐插入数据,可以看到分支节点,叶子节点的变化情况。

我们这个时候可以换个思路,来使用dbms_stats来查看一下信息。
user_indexes中的信息还有比较粗略的。我们来验证一下是否和analyze分析的Index_stats结果一致。

SQL> select blevel,leaf_blocks from user_indexes where index_name=’INX_TEST’;

BLEVEL LEAF_BLOCKS
———- ———–
0 1
这个时候看起来信息过旧了,我们使用dbms_stats来收集一下统计信息。
exec dbms_stats.gather_index_stats(ownname=>’N1′,indname=>’INX_TEST’);
再次查看结果就跟预期的一致了。

select blevel,leaf_blocks from user_indexes where index_name=’INX_TEST’;

BLEVEL LEAF_BLOCKS
———- ———–
1 2

索引的内部信息还是比较抽象的,要做细致的分析还是要下不少的功夫。不过对于索引的很多细节信息,可以说都属于技术级别,都在oracle内部做了封装。我们可以根据兴趣来了解一下。

admin

杨建荣,《Oracle DBA工作笔记》《MySQL DBA工作笔记》作者,dbaplus社群发起人之一,腾讯云TVP,现任竞技世界系统部经理,拥有十多年数据库开发和运维经验,目前专注于开源技术、运维自动化和性能调优

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注