https://blog.csdn.net/biww620/article/details/73003880java
目录是索引的一个最好的例子,每条目录包含对应章节的标题和页码,类比索引的每条索引项包含了数据记录的某些键值组合并包含了对应数据块的访问路径(rowid)。目录的存在就是为了快速定位到感兴趣的内容,索引的存在也是问了加快对表数据的随机访问。sql
经常被说起的索引可能有单键索引、组合索引、惟一索引、B-Tree索引、位图索引、函数索引、全局索引、局部索引等等。这里只是列举出镜率较高的索引类型,并无去作严格的划分,各种型间有重叠,好比函数索引能够是B-Tree索引也能够是位图索引。在Oracle中索引和表同样属于逻辑结构中的段(segment)。每一个索引都拥有独立的结构,不管是从物理结构仍是逻辑结构来看与其所关联的表彻底分开,即使索引失效也不会形成原有SQL没法执行,只是改变了执行计划,下降了执行效率。数据库
B-Tree索引
查找树有彻底二叉树、二叉查找树、平衡二叉树、红黑树,B-Tree,B+-Tree,B*-Tree等。对于二叉树其目的是要将查询复杂度控制在O(lgN)之内。(注:这里的lgN表示log2N),查询效率与树的高度有关。在少许数据构造的二叉树查询是很高效的,可是在数据库应用中,数据量巨大,若是构造二叉树那么树的高度将也很巨大,势必增长读取索引节点的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索引简要分析
1、提升查询效率
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的数据量不大。若是是大数据量的表执行效率的差距会更加明显。
2、索引树高度较低
经过如下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');.net
对于200w条记录的表test_index_t1执行索引统计信息查询后获得的结果为:blog
能够看出BLEVEL = 2也就是说索引树的高度为3。构建了记录数分别为10条,20w条和300w条的表并创建相同的索引,索引树高度分别为2,2,3。所以能够看出B-Tree索引的高度是比较低的,可以在大数据量的状况下保证树高度值很低。在经过索引执行查询时一个层级每每就表明一次I/O操做,所以保持索引树高度较低对查询性能有很大的好处。
3、索引包含键值
索引包含索引键值,单键或键组合,若是查询所需的字段均在索引项中则能够避免回表读数,提升查询性能。建立表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)、(col一、col2)均未回表读数,而第三次查询存在TABLE ACCESS BY INDEX ROWID回表读数,缘由是组合索引INDEX_COL1_COL2中不包含列col3,所以经过索引扫描获得最终记录的rowid后还会根据rowid到表中读取col3。
整体来看,若是所需列包含于索引中那么能够经过索引避免回表读数从而提升查询性能。但须要注意的是索引自己也有性能消耗,并非包含的列越多越好。通常建议索引列不超过3个,从实际的经验来看5,6个也仍是能够接受。
4、索引自己有序
在前面提到的索引结构中能够看出索引叶子结点自己是按照索引键升序排列,至关于一个双向链表,能够进行升序或降序扫描。删除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不存在了。所以,若是由于排序致使查询性能下降能够考虑在索引中包含须要排序的列,这样利用索引自己的有序性能够避免排序带来的性能损耗。
5、索引不保存索引键值所有为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作验证。————————————————版权声明:本文为CSDN博主「biww620」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处连接及本声明。原文连接:https://blog.csdn.net/biww620/java/article/details/73003880