MySQL索引底层数据结构(完善篇)

421 阅读7分钟

1、Hash表

  • 哈希表使用哈希函数将键值转换为哈希值,然后将哈希值映射到哈希表中,定位到对应的存储位置。
  • 哈希索引的优点有:
    • 查询速度快,适合用于高速访问大量数据的场景,通常比存储引擎自身的B树或B+树索引快;
    • 同时哈希索引的内存占用较小,查询速度快,对于一些需要高效查询但数据量不是很大的数据表适用。
  • 然而,哈希索引也有其缺点:
    • 不支持范围查询和排序,只适用于等值查询(仅能满足“=”,“IN”);
    • 同时哈希函数的哈希算法如果设计不当,可能会出现哈希冲突的问题,导致性能会随着数据增多而下降。

在实际的数据库应用场景中,哈希索引通常作为辅助索引来使用,比如MySQL InnoDB引擎中的自适应哈希索引(AHI)技术,它会在B+树索引之外自动构建一个哈希索引,以加速对数据的查找。一般来说,哈希索引和B+树索引结合使用,可以充分发挥各自的优点,提高数据库的查询性能和效率。

hash冲突问题(多个不同的 key 最后得到的 index 相同):

在这里插入图片描述

2、B树和B+树区别,索引选择B、B+树的理由

2.1 树形结构的演变历史

image.png

image.png

二叉树:每个节点最多支持两个分叉

二叉查找树:二叉树为基础,左节点比父节点要小,右节点比父节点要大。它的高度决定的查找效率。

image.png

image.png

如果某一列数据遇到像‘倾斜二叉查找树’,那么这个二叉树索引,其实就成了“链表”,查询此列数据还是全表扫描的方式,就失去了加索引的意义。 树在插入的时候非常有可能导致倾斜,不同的插入顺序会导致树的高度不一样,而树的高度直接影响了树的查找效率。不平衡的二叉查找树自然查找效率更低。

因此,又引入了一种叫做平衡二叉树的机制。

平衡二叉树:二叉查找树为基础。且左右两个子树的高度差的绝对值不能超过1。 为了达到这样一个平衡,所以它会引入一个左旋和右旋的机制,来实现树的平衡。

image.png

image.png

2.2 B树 & B+树

B树(多路平衡查找树)和B+树是一种常用的数据结构,主要用于对有序数据进行存储和访问,例如文件系统和数据库等。

B树:

  1. 每个节点中既储存数据,又储存子节点的指针。(所有节点既存放键(key),也存放数据(data))
  2. B树叶子节点之间没有建立链表,每个叶子节点都是独立的。(叶子节点:没有孩子节点的节点叫作叶子节点;非叶子节点:跟叶子节点相反,有孩子节点的节点)
  3. 当需要进行查找时,只需在B树上一直向下遍历就能够找到想要的记录

B+树在B树的基础上进行了优化,它采用类似于B树的结构

  1. 所有的数据都存储在叶子节点中,非叶子节点只包含键和对应子节点的指针。(只有叶子节点存放 key 和 data,其他内节点只存放 key)
  2. 同时,将所有叶子节点之间连接成了一个有序链表,方便范围查询和顺序遍历操作。(适合MySQL中常见的基于范围的顺序查找,而B树无法做到这一点)
  3. 进行查找时,B+树索引先进入一颗非叶子节点区域,再由它遍历到叶子节点区域。

B树和B+树在节点中可以存储的元素数量与块的大小有关。B/B+树一个节点可以有多个元素,节点里面的元素都是排好序的

数据库B+Tree对于B-Tree优化思路有

  1. 非叶子节点data,只存储索引,可以放更多的索引。
  2. 所有叶子节点之间都有一个链指针(顺序访问指针,可以提高访问的性能)。
  3. 数据记录都存放在叶子节点中,查询性能稳定,B树查找最坏情况下到叶子节点。

2.3 选择B树和B+树的理由

选择B树或者B+树作为索引结构,主要是为了减少磁盘IO的次数(MySQL 的数据是存储在磁盘中的)

因为ALV树(平衡二叉树) 的高度要比B树或者B+树的高度更高,而高度就意味着磁盘IO的数量,所以,为了减少磁盘IO的次数,文件系统或者数据库才会使用B树,或者B+树来做索引结构。

在比较经典的程序应用中,MongoDB使用的是B树,MongoDB中所有的节点都有Data域,只要找到指定索引就可以进行访问,无疑单次查询会更快。

而MySQL作为一个关系型数据库,数据的关联性是非常强的,区间访问是常见的一种情况,B+树由于数据全部存储在叶子节点,并且通过指针串在一起,这样就很容易的进行区间遍历甚至全部遍历。

3、红黑树

3.1 红黑树概述

又做二叉平衡树,本质还是一棵二叉树。解决二叉树一边倒的可能性。平衡树在插入和删除的时候,会通过旋转操作将树的左右节点达到平衡(红黑树可以自动平衡,这样就解决了“倾斜二叉查找树”的问题)。

红黑树性质:

  1. 每个节点要么是黑色,要么是红色。
  2. 根节点是黑色。
  3. 每个红色节点的两个子节点都为黑色。
  4. 从任一节点出发到其每个叶子节点的路径,黑色节点的数量都相等。

有了上面的几个性质作为限制,即可避免二叉查找树退化成单链表的情况。但是,仅仅避免这种情况还不够,这里还要考虑某个节点到其每个叶子节点路径长度的问题。如果某些路径长度过长,那么,在对这些路径上的节点进行增删查操作时,效率也会大大降低。这个时候性质3和性质4用途就凸显了,有了这两个性质作为约束,即可保证任意节点到其每个叶子节点路径最长不会超过最短路径的2倍。原因如下:

当某条路径最短时,这条路径必然都是由黑色节点构成。当某条路径长度最长时,这条路径必然是由红色和黑色节点相间构成(性质3限定了不能出现两个连续的红色节点)。而性质4又限定了从任一节点到其每个叶子节点的所有路径必须包含相同数量的黑色节点。

此时,在路径最长的情况下,路径上红色节点数量 = 黑色节点数量。该路径长度为两倍黑色节点数量,也就是最短路径长度的2倍。

这些约束强制了红黑树的关键性质: 从根到叶子的最长的可能路径不多于最短的可能路径的两倍长。结果是这个树大致上是平衡的。因为操作比如插入、删除和查找某个值的最坏情况时间都要求与树的高度成比例,这个在高度上的理论上限允许红黑树在最坏情况下都是高效的,而不同于普通的二叉查找树。

3.2 红黑树效率如此之高,MySQL为何不采用?

在实际场景应用当中,MySQL表数据,一般情况下都是比较庞大、海量的。如果使用红黑树,树的高度会特别高,红黑树虽说查询效率很高。但是在海量数据的情况下,树的高度并不可控。如果我们要查询的数据,正好在树的叶子节点。那查询会非常慢。故而MySQL并没有采用红黑树来组织索引。