一直只知道数据库索引可以提高查询效率,但数据库索引具体的实现一直不太清楚,看了一些文章,这里进行一个总结。
本文的目的是对数据库索引的基本概念进行介绍,不进行深入的探讨。
一、索引基础
1、概念
索引是定义在存储表基础之上,有助于无需检查所有记录而快速定位所需记录的一种辅助存储结构,由一系列存储在磁盘上的索引项(index entries)组成。索引项由两部分组成:
- 索引字段:table中的某些列,如id等;类似于词典中的词条
- 索引指针:指向table中包含索引字段值的记录在磁盘上的存储位置。类似于词典中词条对应的页码
2、分类
按不同分类方法, 顺序索引可以分为:稠密索引与稀疏索引(数据与索引的对应关系)、主索引与辅助索引、聚簇索引与非聚簇索引(数据与索引的存储顺序)、倒排索引、多级索引、散列索引等等。
表:几种索引类型表
| 索引类型 | 概念 | 特点 |
|---|---|---|
| 稠密索引 | 对于主文件中每一个记录(形成的每一个索引字段值),都有一个索引项和他对应,指明该记录的位置 | 查询效率高,但占用空间大,维护任务大 |
| 稀疏索引 | 对于主文件中部分记录(形成的索引字段值),有索引项和他对应 | 空间占用少,维护任务更轻,但速度更慢 |
| 主索引 | 对每一个存储块有一个索引项,索引项的总数和存储表所占的存储块数目相同。 | - 属于稀疏索引; |
| 辅助索引 | 是定义在主文件的任一或多个非排序字段上的辅助存储结构。辅助索引通常是对某一非排序字段上的每一个不同值有一个索引项:索引字段即是该字段的不同值; | 属于稠密索引 |
| 聚簇索引 | 在索引中邻近的记录在主文件中也是邻近存储的; | 通常是主索引 |
| 非聚簇索引 | 在索引中邻近的记录在主文件中不一定是邻近存储的; | 通常是非聚簇索引 |
| ..... |
二、B+树索引
B+树索引,是在数据插入和数据删除下仍能保持其执行效率的几种使用最广泛的索引结构之一。
B+树索引采用平衡树结构,这种结构的树高度很小,索引本身占用的内存很小,还可存储大量的数据,因此大多数数据库系统均采用B+树索引结构。
B+树索引结构如下图所示:
B+树索引结构如下图所示,其中:
- 每一个树节点由一个搜索码和一个指针组成
- 非叶节点(根节点及内部节点)仅记录参与索引的字段值,以及下一级的指针
- 叶子节点存储参与索引的字段值及指向数据记录的指针
- 各叶节点之间按搜索码大小有一个线性的顺序,叶子节点拥有指向下一个叶子节点的指针,这种结构便于对数据进行高效的顺序处理。
- 一般性情况,数据库的B+树的高度一般在2~4层,这就是说找到某一键值的行记录最多需要2到4次逻辑IO,相当于0.02到0.04s。
三、数据库中的B+树索引结构
数据库中的每一个索引都对应一个索引文件,包括聚集索引、非聚集索引、联合索引等。
1、聚集索引结构
按建立聚集索引的字段建立B+树索引,表中的数据按建立聚集索引的字段在磁盘上进行排序,每张表只能有一个聚集索引(只能有一种排序方式)。
- 聚集索引的根节点和中间节点是索引页,都只包含下一层的入口指针和入口值(位于存储位置的第一个主键值);
- 聚集索引的叶节点就是数据页。存放了表里所有字段的数据
聚集索引是一种对磁盘上实际数据重新组织以按指定的一列或多列值排序。由于在聚集索引下,数据在物理上是按序排列在数据页上的,重复值也排在一起,因而包含范围检查(bentween,<,><=,>=)或使用group by 或order by的查询时,一旦找到第一个键值的行,后面都将是连在一起,不必在进一步的搜索,避免大范围的扫描,可以大大提高查询速度。
2、非聚集索引
非聚集索引不重新组织表中的数据,一个表中可以有多个非聚集索引。
通过非聚集索引查询数据需首先找到聚集索引,再通过聚集索引获取实际的数据。相比聚集索引多了一倍io。
具体结构如下:
- 非聚集索引的根节点和中间节点是索引页,都只含下一层级的入口指针和入口值(位于存储位置的第一个键值);
- 非聚集索引的叶节点也是索引页,也存储有聚集索引和非聚集索引的键值;
- 非聚集索引中的每个索引行(不论是根节点、中间节点还是叶节点)都包含非聚集键值和行定位符,此定位符指向聚集索引或堆(没有聚集索引的表)中包含该键值的数据行。
非聚集索引概念关系图如下:
四、什么时候建立索引
索引技术应用可以使得检索效率大大提高,但同时其增加了存储空间,使维护负担加重(不仅要维护主文件,而且要维护索引文件),而且聚集索引每张表只能有一个,因此在什么字段上建立索引和建立什么样的索引尤为重要。
一般建立索引的原则包括以下内容:
-
大的原则:经常出现在检索条件,连接条件,分组计算条件中的属性应该建立聚集索引;
-
在一个经常做插入操作的表中建立索引,应使用fillfactor(填充因子)来减少页分裂,同时提高并发度降低死锁的发生。如果在表为只读表,填充因子可设为100;
-
在选择索引键时,尽可能采用小数据类型的列作为键以使每个索引页能容纳尽可能多的索引键和指针,通过这种方式,可使一个查询必需遍历的索引页面降低到最小,此外,尽可能的使用整数做为键值,因为整数的访问速度最快;
-
如果大多数处理都只涉及某个大表的某些列,可以考虑为这些列建立覆盖索引;
一些误区:
- 自增类型的主键id作为聚集索引
通常情况下,我们会在每张表中建立一个id作为主键,但检索的时候如果不用id号来进行查询的话,就失去了作为聚集索引的意义,浪费了聚集索引这一宝贵的资源
参考资料
强烈建议哈工大的《数据库系统》课程,中国大学MOC和B站上都有课程视频
聚集索引与非聚集索引的总结 www.cnblogs.com/s-b-b/p/833… 数据库索引 www.cnblogs.com/amou/p/9523…
SqlServer索引的原理与应用 www.cnblogs.com/knowledgese…
SQL Server 存储(1/8):理解数据页结构 blog.csdn.net/yangmeng518…