关于索引的内部信息(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内部做了封装。我们可以根据兴趣来了解一下。
- silverlight 2 Random 随机数解决方案
- 开发中巧用Enum枚举类型
- Jquery 事件冒泡
- Vue2的单元测试与调试技术
- silverlight beta 2 将在本周末发布.
- [Silverlight 4 RC]WebBrowser概览
- 英文域名chosen.com超22万元易主
- 简单介绍Docker的架构特性与局限
- .NET4.0下网站应用程序用UrlRewriter.dll重写无后缀路径 (在IIS7.5中的配置方法)
- 微信搜索新发现:iPhone 内存不足看这里!
- 建立可扩展的silverlight 应用框架 step-6
- .NET4.0下网站应用程序用UrlRewriter.dll重写无后缀路径 (在IIS7.5中的配置方法)
- 苹果为你的心跳开发一个读者
- 建立可扩展的silverlight 应用框架 step-5
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- spark shell 配置 Kryo 序列化
- Mac里捣腾Kerberos(一)
- Spark on K8S 访问 Kerberized HDFS
- Apache Beam的Docker Demo
- docker login 报错了...
- Spark-Submit 和 K8S Operation For Spark
- Spark的Dockerfile分析
- Spark on Kubernetes在Mac的Demo
- Python的Wand模块
- 机器学习第4天:预测1立方米混凝土抗压强度
- 硬件笔记之GP106-90 3GB GTX1060 3GB魔改
- Java BigDecimal 的舍入模式(RoundingMode)详解
- 实际工程中加快 Java 代码编写的小提示
- CentOS7 离线安装软件并准备依赖包
- CentOS7 SkyWalking APM8.1.0 搭建与项目集成使用