MySQL-索引的数据结构
- 因为MySQL的索引具体的数据结构实现实在存储引擎中的,因此不同的存储引擎可能使用不同的数据结构来实现索引。
- 索引中常用的三种数据结构为:B树(也称B-树)、B+树、哈希。
-
B树
-
一种平衡的多叉树。
-
显著减少定位记录时所*经历的中间过程
-
节点
- B树的每一个节点由n个key和n+1个指向下一层节点的指针构成。
-
阶
- 对于一棵m阶B-tree,每个节点至多可以拥有m个子结点(指向下一层节点的指针数量)。
-
定义
-
一棵m阶的B树满足下列条件:
-
(1)根节点 或者是叶子节点、或着其子节点数在2和M之间。
-
(2)除根结点外,其余所有结点的子节点数大于
m/2(向大取整)
小于m
。 -
(3)所有叶子结点在同一层。
-
(4)有m-1个key的节点有m个指向子节点的指针。
-
-
查找
- 首先在根结点所包含的key查找给定的key(可用顺序查找或二分查找法)。
- 若找到给定key,则查找成功。
- 否则,确定要查找的key在哪两个Ki与Ki+1之间,对应的Pi为指向此区间子树节点的指针。
- 此时取指针Pi所指的结点继续查找,直至找到,或指针Pi为空时查找失败。
-
插入
- 设插入的树当前阶数为m
- (1)根据要插入的key值,找到叶子结点并插入。
- (2)判断当前结点key的个数是否小于等于m-1,若满足则结束,否则进行第3步。
- (3)以结点中间的key为中心分裂成左右两部分,然后将这个中间的key插入到父结点中,这个key的左指针指向分裂后的左半部分,这个key的右指针指向分裂后的右半部分,然后继续进行第3步判断当前节点父节点的key的个数是否超过m-1。
以下图的3阶B树为例插入。
-
删除
- 1.如果当前需要删除的key位于非叶子结点上,则用后继key覆盖要删除的key(此后继key一定位于叶子结点上)
- 2.然后在后继key所在的叶子节点中删除该后继key,将此后继key所在节点设定为当前节点。
- 3.当前结点key个数大于等于m/2个(向上取整)-1个子节点,结束删除操作,否则执行第4步。
- 4.如果兄弟结点key个数大于m/2个(向上取整)-1个子节点,则父结点中的key下移到该结点,兄弟结点中的一个key上移,删除操作结束。
- 5.否则,将父结点中的key下移与当前结点及它的兄弟结点中的key合并,形成一个新的结点。原父结点中的key的两个孩子指针就变成了一个孩子指针,指向这个新结点。
- 然后将父结点设定为当前节点,重复第3步,防止父节点key的数量过少。
- 借用兄弟节点的key来删除:
- 合并兄弟节点删除:
-
-
B+树
-
B+树是B树的一种变形,比B树具有更广泛的应用。
-
B+树在节点访问时间远远超过节点内部访问时间的时候,比可作为替代的实现有着实在的优势。
-
通过最大化在每个内部节点内的子节点的数目减少树的高度,平衡操作不经常发生,而且效率增加了。这种价值得以确立通常需要每个节点在次级存储中占据完整的磁盘块或近似的大小。
-
定义
- B+树上的叶子结点存储key以及key对应的地址,叶子结点以上各层作为索引使用不存储信息。
- 一棵m阶的B+树定义如下:
- (1)每个结点至多有m个子节点(指向子节点的指针)。
- (2)除根结点外,每个结点至少有m/2个key,最多m个key。
- (3)除叶子节点以外的所有内部节点有相同的子节点和key的个数。(此处含有歧义,有的解释为可以key个数=子节点个数-1,但在本文中同维基百科一样按照相同来定义)
- (4)所有叶子节点都在相同的高度上,叶子结点本身按关键字大小从小到大链接。
-
节点
- 非叶子节点的子节点指针所指向的子节点的key范围含有歧义,这里假设为子节点的key均小于等于此key。
- 非叶子节点中不存储key对应的数据。
- 叶子节点中含有指向后继叶子节点的指针,便于范围遍历取值。
-
查找
- (1)首先在根结点所包含的key中查找给定的key对应的区间的子节点指针(可用顺序查找或二分查找法)。
- (2)若存在则将对应的Pi改为指向此区间子节点的指针,不存在则查找失败。
- (3)此时取指针Pi所指的结点继续查找,直至Pi在叶子节点中或对应范围指针不存在。
- (4)当Pi在叶子节点时,若找到此叶子节点中包含此key则返回对应的data并结束查找,否则查找失败。
- 注:若为范围查找,则在第四步找到范围的起始key时根据后继指针来进行范围查找即可。
-
插入与删除
- 插入与删除操作同内部节点是否有相同的子节点和key的个数有关。
- 因为此处存在歧义,并不对过程做具体解释。
- (1)不相同
- 删除与插入同B树几乎一样。
- (2)相同
- 插入只需考虑当key大于根节点的最后一个key范围时,应在根节点中加入此key的索引,并依次向下创建新的子节点直到叶子节点为止,并需要考虑创建的子节点的key个数过小应向兄弟节点或与兄弟节点合并的问题。
- 其他步骤同B树的插入类似,先插入,判断key个数,选择相应的策略来调整节点。
-
-
B树与B+树的对比
- B+树磁盘IO次数少
- B树中每个节点中既要存key,又要存其对应的数据,如果数据很大,那么当树的体量很大时,每次从磁盘中读到内存的key的个数就变小了,因此磁盘IO次数将过多。
- B+树便于范围查找
- B树+不利于范围查找,需要通过类似于中序遍历的方式来进行范围查找,而B+树在叶子节点中含有后继指针,便于范围查找。
- B+树查询速度稳定
- B树key与data存在一起因此key所在节点在树中的层并不相同,而B+树均在叶子节点中,因此B+树的查询速度更加稳定。
- B+树磁盘IO次数少
-
哈希索引
- 哈希索引采用的数据结构为散列表。
- 通过将key传入散列函数中得到其对应的hash值,并将此key及对应的数据存到数组中此hash值的位置。
- 若不同key得到了同一hash值(哈希碰撞),则在数组的此位置上拉链表。
-
哈希索引与B树/B+树的对比
- 在不发生哈希碰撞或碰撞较少时,哈希索引相当于数组,其查找速度远大于B树/B+树。
- 哈希索引之支持等值比较不支持大于小于。
- 哈希索引不支持范围查找,因此排序也无优化。
- 哈希联合索引为多个字段一起求哈希,因此不可拆开用。