Oracle学习笔记(一)——B-Tree索引

        目录是索引的一个最好的例子,每条目录包含对应章节的标题和页码,类比索引的每条索引项包含了数据记录的某些键值组合并包含了对应数据块的访问路径(rowid)。目录的存在就是为了快速定位到感兴趣的内容,索引的存在也是问了加快对表数据的随机访问。

        常常被提及的索引可能有单键索引、组合索引、唯一索引、B-Tree索引、位图索引、函数索引、全局索引、局部索引等等。这里只是列举出镜率较高的索引类型,并没有去做严格的划分,各类型间有重叠,比如函数索引可以是B-Tree索引也可以是位图索引。在Oracle中索引和表一样属于逻辑结构中的段(segment)。每个索引都拥有独立的结构,无论是从物理结构还是逻辑结构来看与其所关联的表完全分开,即便索引失效也不会造成原有SQL无法执行,只是改变了执行计划,降低了执行效率。

B-Tree索引

        查找树有完全二叉树、二叉查找树、平衡二叉树、红黑树,B-Tree,B +-Tree,B *-Tree等。对于二叉树其目的是要将查询复杂度控制在O(lgN)以内。(注:这里的lgN表示log 2N),查询效率与树的高度有关。在少量数据构造的二叉树查询是很高效的,但是在数据库应用中,数据量巨大,如果构造二叉树那么树的高度将也很巨大,势必增加读取索引节点的I/O次数,影响查询效率。于是B-Tree挺身而出,在很大的数据量范围内能够保持B-Tree树的层级不会增加。

图片来自网络

从上图中可以看出在oraccle中B-Tree索引具有以下结构特点:
  • B-Tree索引包含根节点(Root Node)、分支节点(Branch Node)和叶子节点(Leaf Node)。
  • 索引树高度一般都很低,上百亿记录的索引树的高度也只有5,6层。
  • 索引本身有序。叶子节点是一个双向链表,因此可以按照索引的升序或降序进行索引扫描。
  • 索引项包含键值信息和ROWID。索引项由索引头部、索引列的长度、索引值以及对应记录的rowid。其中唯一索引对应的rowid是唯一的,非唯一索引对应的rowid是可能有多个(多个rowid是有序的)。
  • 索引列值全部为NULL的索引项是不会被记录的。

B-Tree索引简要分析

一、提高查询效率

200w条记录的表test_index_t1,查找条件col1 = 98765的记录没有索引的执行计划如下:


在test_index_t1表的col1列添加索引
create index index_col1 on test_index_t1(col1);
再次执行查询的执行计划如下:

未建立索引时执行计划是TABLE ACCESS FULL用时1100ms,建立索引后执行计划是INDEX RANGE SCAN用时90ms,效率提高了10倍以上。这里test_index_t1的数据量不大。如果是大数据量的表执行效率的差距会更加明显。

二、索引树高度较低

通过以下sql可以查询索引的统计信息,其中BLEVEL表示索引树的高度,高度为BLEVEL +  1
SELECT
    index_name,
    blevel,
    leaf_blocks,
    num_rows,
    distinct_keys,
    clustering_factor
FROM
    user_ind_statistics
WHERE
    table_name = UPPER('test_index_t1');

对于200w条记录的表test_index_t1执行索引统计信息查询后得到的结果为:

        可以看出BLEVEL = 2也就是说索引树的高度为3。构建了记录数分别为10条,20w条和300w条的表并建立相同的索引,索引树高度分别为2,2,3。因此可以看出B-Tree索引的高度是比较低的,能够在大数据量的情况下保证树高度值很低。在通过索引执行查询时一个层级往往就代表一次I/O操作,因此保持索引树高度较低对查询性能有很大的好处。

三、索引包含键值

       索引包含索引键值,单键或键组合,如果查询所需的字段均在索引项中则可以避免回表读数,提高查询性能。创建表test_index_t1包含三个字段col1,col2,col3初始化为300w条记录,并建立了(col1,col2)组合索引。
create index index_col1_col2 on test_index_t1(col1, col2);
1. 执行sql 
select col1 from test_index_t1 where col1 between 10 and 20;

2. 执行sql
select col1, col2 from test_index_t1 where col1 between 10 and 20;


3. 执行sql
select * from test_index_t1 where col1 between 10 and 20;
从上面三次查询结果可以看出:
     (1) 三次执行SQL均用到了索引INDEX_COL1_COL2,索引执行方式为Index Range Scan
     (2) 第一次和第二次查询(col1)、(col1、col2)均未回表读数,而第三次查询存在TABLE ACCESS BY INDEX ROWID回表读数,原因是组合索引INDEX_COL1_COL2中不包含列col3,因此通过索引扫描得到最终记录的rowid后还会根据rowid到表中读取col3。
      总体来看,如果所需列包含于索引中那么可以通过索引避免回表读数从而提高查询性能。但需要注意的是索引本身也有性能消耗,并不是包含的列越多越好。一般建议索引列不超过3个,从实际的经验来看5,6个也还是可以接受。

四、索引本身有序

      在前面提到的索引结构中可以看出索引叶子结点本身是按照索引键升序排列,相当于一个双向链表,可以进行升序或降序扫描。删除test_index_t1表的索引,再执行查询
 select col1, col2 from test_index_t1 where col1 between 10 and 20 order by col1;

从执行计划和统计信息中可以看出执行了排序过程并使用了内存空间。给test_index_t1表col1字段加上索引后的执行计划如下

        执行计划走索引后SORT ORDER BY不存在了。因此,如果因为排序导致查询性能降低可以考虑在索引中包含需要排序的列,这样利用索引本身的有序性可以避免排序带来的性能损耗。

五、索引不保存索引键值全部为NULL的记录

         这个特点跟count,sum/avg,max/min的执行计划息息相关,可以总结为以下两点:
  • COUNT/SUM/AVG必须在索引列为非空的情况下才可以走到索引。(建表是列指定为Not Null或为主键或在where条件中指明为is not null)。
  • MIN/MAX则不会受到空值的影响,均能走到索引。
表test_index_t1有300w条记录,在col1上建立了索引,执行:
select count(1) from test_index_t1;

可以看出是走了全表扫描。在where条件中增加col1 is not null后的执行计划为:

用INDEX FAST FULL SCAN的方式使用索引INDEX_COL1。最后col1添加属性not null后的执行计划为:

可以看出给列col1添加了not null属性后执行计划跟在where条件中指明is not null相同。这里不再对sum/avg,min/max做验证。
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值