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

时间:2022-05-04
本文章向大家介绍关于索引的内部信息(r3笔记第83天),主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

在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内部做了封装。我们可以根据兴趣来了解一下。