研发分享会:数据库的索引

12 篇文章 0 订阅
4 篇文章 0 订阅

数据库的索引

一、前言

本节主要介绍数据库中的索引的所用到的数据结构和索引的用途。

二、B-树

2.1 索引使用的数据结构

我们常见的数据库系统,其索引使用的数据结构多是B-Tree或者B+Tree。例如,MsSql使用的是B+Tree,Oracle及Sysbase使用的是B-Tree

2.2 B-树的介绍

B-Tree不同于Binary Tree(二叉树,最多有两个子树),一棵M阶的B-Tree满足以下条件:

1.根结点至少有两个子女。

2.每个中间节点都包含k-1个元素和k个孩子,其中 m/2 <= k <= m(元素数总比孩子数少一个

3.每一个叶子节点都包含k-1个元素,其中 m/2 <= k <= m

4.所有的叶子结点都位于同一层

5.每个节点中的元素从小到大排列,节点当中k-1个元素正好是k个孩子包含的元素的值域分划。(例如:两个节点划分为三个孩子节点

img

img

img

对于每个结点,主要包含一个关键字数组Key[],一个指针数组(指向儿子)Son[]。在B-Tree内,查找的流程是:使用顺序查找(数组长度较短时)或折半查找方法查找Key[]数组,若找到关键字K,则返回该结点的地址及K在Key[]中的位置;否则,可确定K在某个Key[i]和Key[i+1]之间,则从Son[i]所指的子结点继续查找,直到在某结点中查找成功;或直至找到叶结点且叶结点中的查找仍不成功时,查找过程失败。

2.3 B-树的插入

一个原始的B-树阶为3,如下图:

510669

首先,我需要插入一个关键字:30,可以得到如下的结果:

510669

再插入26,得到如下的结果:

510669

OK,此时如图所示,在插入的那个终端结点中,它的关键字数已经超过了m-1=2,所以我们需要对结点进分裂,所以我们先对关键字排序,得到:26 30 37 ,所以它的左部分为(不包括中间值):26,中间值为:30,右部为:37,左部放在原来的结点,右部放入新的结点,而中间值则插入到父结点,并且父结点会产生一个新的指针,指向新的结点的位置,如下图所示:

510669

OK,然后我们继续插入新的关键字:85,得到如下图结果:

510669

正如图所示,我需要对刚才插入的那个结点进行“分裂”操作,操作方式和之前的一样,得到的结果如下:

510669

哦,当我们分裂完后,突然发现之前的那个结点的父亲结点的度为4了,说明它的关键字数超过了m-1,所以需要对其父结点进行“分裂”操作,得到如下的结果:

三、B+树

3.1 B+树的定义

clip_image039

各种资料上B+树的定义各有不同,一种定义方式是关键字个数和孩子结点个数相同。这里我们采取维基百科上所定义的方式,即关键字个数比孩子结点个数小1,这种方式是和B树基本等价的。上图就是一颗阶数为4的B+树。

除此之外B+树还有以下的要求。

1)B+树包含2种类型的结点:内部结点(也称索引结点)和叶子结点。根结点本身即可以是内部结点,也可以是叶子结点。根结点的关键字个数最少可以只有1个。

2)B+树与B树最大的不同是内部结点不保存数据,只用于索引,所有数据(或者说记录)都保存在叶子结点中。

3)(这条区别是有争议的,有人说B+树的节点中关键字和子节点个数相同,也有人说B+树和B树一样关键字比子节点少一个。

4)内部结点中的key都按照从小到大的顺序排列,对于内部结点中的一个key,左树中的所有key都小于它,右子树中的key都大于等于它。叶子结点中的记录也按照key的大小排列。

5)每个叶子结点都存有相邻叶子结点的指针,叶子结点本身依关键字的大小自小而大顺序链接。(所有的叶子节点组成单向链表

3.2 B+卫星数据

Satellite Information

3.2.1 B-树中的卫星数据

img

3.2.2 B+树中的卫星数据

img

在数据库的聚集索引(Clustered Index)中,叶子节点直接包含卫星数据。在非聚集索引(NonClustered Index)中,叶子节点带有指向卫星数据的指针

3.3 B+树的优势

img

img

img

img

B+树的优势:

1.单一节点存储更多的元素,使得查询的IO次数更少。

2.所有查询都要查找到叶子节点,查询性能稳定。

3.所有叶子节点形成有序链表,便于范围查询。

四、数据库索引

4.1 什么是索引 ?

image.png

image.png

image.png


4.1.1 索引的优势

在数据库中,索引的含义与日常意义上的“索引”一词并无多大区别(想想小时候查字典),它是用于提高数据库表数据访问速度的数据库对象
A)索引可以避免全表扫描(从头找到尾)。多数查询可以仅扫描少量索引页及数据页,而不是遍历所有数据页(用于存储记录的页被称为数据页,大小也为16KB)。
B)对于非聚集索引,有些查询甚至可以不访问数据页。
C)聚集索引可以避免数据插入操作集中于表的最后一个数据页。
D)一些情况下,索引还可用于避免排序操作。

当然,众所周知,虽然索引可以提高查询速度,但是它们也会导致数据库系统更新数据的性能下降,因为大部分数据更新需要同时更新索引。

4.1.2 索引为什么用B+ 树?

image.png

计算机中的存储结构分为好几个部分,从上到下大致可以分为寄存器、高速缓存、主存储器、辅助存储器。其中主存储器,也就是我们常说的内存;辅助存储器也被称为外存,比较常见的就是磁盘、SSD,可以用来保存文件。在这个存储结构中,每一级存储的速度都比上一级慢很多,所以程序访问越上层存储中的数据,速度就会越快。

有过编程经验的小伙伴都知道,程序运行过程中操作的基本都是内存,对外存中数据的访问往往需要写一些文件的读取和写入代码才能实现。这正是因为CPU的计算速度比存储的I/O速度(输入/输出速度)快很多所做的优化,因为CPU在每次计算完成之后就需要等待下一批的数据进入,这个等待的时间越短,计算机运行得越快。

所以对于数据库索引来说,因为数据量很大,所以基本都是保存在外存中的,这样的话数据库读取一个索引节点的成本就非常大了。在数据量一样大的情况下,我们可以知道,B+树的单个节点中包含的值个数越多那么树中需要的节点总数就会越少,这样查询一次数据需要访问的节点数就更少了。

如果我们把二叉树看做是特殊的B+树(每个节点只有一个值和前后两个指针的B+树),那么就可以得出结论:**因为B+树的节点中包含的值个数(多个值)比二叉树(1个值)更多,所以在B+树中查询所需要的节点数就更少。**那么如果每次读取的成本是一样的话,因为总成本=读取次数*单次读取成本,我们就可以证明B+树的查询成本就比二叉树小得多了。

4.2 什么是联合索引?

相信大家都见过一些包含多个字段的数据库索引,比如INDEX idx_test(col_a, col_b)。这种包含多个字段的索引就被称为**“联合索引”**。那么在多个字段上建索引能起到什么样的作用呢?下面还是以新华字典为例,来看看到底什么是联合索引。

新华字典里还有一种目录被称为“部首目录”,下面可以看到,要使用这个目录我们首先会根据部首的笔画数找到对应该能的部分,然后可以在里面找到我们想找的部首。比如如果我们还是要找字所在的位置:

image.png

找到部首后,右边的页码还不是字真正的页码,我们还需要根据右边的页码找到对应部首在检字表中的位置。找到第93页的检字表后我们就可以根据字余下的笔画数(7画)在“6-8画”这一部分里找到字真正的页码了。

image.png

在这个过程中,我们按顺序使用了“两个目录”,一个叫做“部首目录”,一个叫做“检字表”。并且我们可以看到上图中检字表的内容都是按部首分门别类组织的。这两个部分合在一起就是我们在本节讨论的主题——联合索引。即通过第一个字段的值(部首)在第一级索引中找到对应的第二级索引位置(检字表页码),然后在第二级索引中根据第二个字段的值(笔画)找到符合条件的数据所在的位置(字的真正页码)。

4.3 什么是聚集索引?

4.3.1 用字典理解

从上文的部首目录和拼音目录同时存在但是实际的字典内容只有一份这一点上可以看出,在数据库中一张表上是可以有多个索引的。那么不同的索引之间有什么区别呢?

我们在新华字典的侧面可以看到一个V字形的一个个黑色小方块,有很多人都会在侧面写上A, B, C, D这样对应的拼音字母。因为字典中所有的字都是按照拼音顺序排列的,有时候直接使用首字母翻开对应的部分查也很快。

image.png

像拼音目录这样的索引,数据会根据索引中的顺序进行排列和组织的,这样的索引就被称为聚集索引。

而非聚集索引就是其他的一般索引。因为数据只能按照一种规则排序,所以一张表至多有一个聚集索引,但可以有多个非聚集索引。

4.3.2 索引的类型(官方)

A)聚集索引,表数据按照索引的顺序来存储的。对于聚集索引,叶子结点即存储了真实的数据行,不再有另外单独的数据页。
B)**非聚集索引,表数据存储顺序与索引顺序无关。**对于非聚集索引,叶结点包含索引字段值及指向数据页数据行的逻辑指针,该层紧邻数据页,其行数量与数据表行数据量一致。

在一张表上只能创建一个聚集索引,因为真实数据的物理顺序只可能是一种。**如果一张表没有聚集索引,那么它被称为“堆集”(Heap)。**这样的表中的数据行没有特定的顺序,所有的新行将被添加的表的末尾位置。

4.4 数据库索引的具体实现

4.4.1 聚集索引

下面是一个以B+树形式组织的拼音索引,在B+树中,每一个节点里都有N个按顺序排列的值,且每个值的中间和节点的头尾都有指向下一级节点的指针。在查找过程中,按顺序从头到尾遍历一个节点中的值,当发现要找的目标值恰好在一个指针的前一个值之后、后一个值之前时,就通过这个指针进入下一级节点。当最后到达叶子节点,也就是最下层的节点时,就能够找到自己希望查找的数据记录了。

image.png

在上图中如果希望找到字,那么我们首先通过拼音首字母在根节点上按顺序查找到了XY之间的指针,然后通过这个指针进入了第二级节点···, xia, xian, xiang, ···。之后在该节点上找到了xianxiang之间的指针,这样就定位到了第519页开始的一个目标数据块,其中就包含了我们想要找到的字。

因为拼音索引是聚集索引,所以我们在叶子节点上直接就找到了我们想找的数据。

4.4.2 非聚集索引

下面是一个模拟部首索引的组织形式。我们由根节点逐级往下查询,但是在最后的叶子节点上并没有找到我们想找的数据,那么在使用这个索引时我们是如何得到最终的结果的呢?回忆之前字典中“检字表”的内容,我们可以看到,在每个字边上都有一个页码,这就相当于下面这一个索引中叶子节点上字与字中间的指针,这个指针会告诉我们真正的数据在什么地方。

image.png

下图中,我们把非聚集索引(部首索引)和聚集索引(拼音索引)合在一起就能看出非聚集索引最后到底如何查找到实际数据了。非聚集索引叶子节点上的指针会直接指向聚集索引的叶子节点,因为根据聚集索引的定义,所有数据都是按聚集索引组织存储的,所以所有实际数据都保存在聚集索引的叶子节点中。而从非聚集索引的叶子节点链接到聚集索引的叶子节点查询实际数据的过程就叫做——回表

image.png


参考资料

漫谈数据库索引_知识库_博客园

常见面试题整理–数据库篇(每位开发者必备) - 知乎

五分钟搞懂什么是B-树(全程图解)_热点分享_社区_115,一生相伴

漫画:什么是B-树? - 知乎

漫画:什么是B+树? - 知乎

关于B树的学习总结和B+树,B*树的简介 - lkforce - CSDN博客

数据库索引是什么?新华字典来帮你 - 掘金

u.com/p/54084335)

漫画:什么是B+树? - 知乎

关于B树的学习总结和B+树,B*树的简介 - lkforce - CSDN博客

数据库索引是什么?新华字典来帮你 - 掘金

数据库索引融会贯通 - 掘金

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值