索引
数据查询是数据库的最常用的功能之一。我们都希望查询数据的速度能尽可能的快,在MySQL的帮助文档中8.3(https://dev.mysql.com/doc/refman/8.0/en/optimization-indexes.html)中写到:最好的提高数据查询(select)操作的办法就是给需要查询的数据列创建索引。索引可以帮助快速找到查询条件(where)中匹配的数据行,取到需要的数据。所有的MySQL数据类型都可以被索引。但是索引也会消耗磁盘空间,而且当数据库的记录进行插入,更新和删除等操作时,由于索引也需要更新,会增加以上操作的消耗时间。因此索引的添加也必须在以上查询和更新的性能之间找到 一个平衡点。索引的数据结构
目前大部分数据库系统及文件系统都采用B树或其变种B+树作为索引结构。而MySQL也是选择B+树作为其大多数数据类型的索引结构。为什么B树或其变种B+树会被如此广泛地应用于索引呢,下面我们先简单地介绍着两种数据结构。B树和B+树
在计算机科学中,树(英语:tree)是一种抽象数据类型(ADT)或是实现这种抽象数据类型的数据结构,用来模拟具有树状结构性质的数据集合。它是由n(n>0)个有限节点组成一个具有层次关系的集合。把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,叶朝下的。

关于树还有些术语如下:

  • 节点的度:一个节点含有的子树的个数称为该节点的度;
  • 树的度:一棵树中,最大的节点度称为树的度;
  • 叶节点:度为零的节点;
  • 节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推;

AVL树又称高度自平衡的二叉查找树,所谓平衡是指:

  • 左子树和右子树的高度之差的绝对值不超过1
  • 树中的每个左子树和右子树都是AVL树

AVL树很重要的一个性质就是:

  • 一棵AVL树有N个节点,其高度可以保持在lgN,插入/删除/查找的时间复杂度也是lgN。

B树一种对读写操作进行优化的AVL树,拥有多于两个子树,一棵度数(order)为m的B树有如下特性:

  • 每个节点最多有m个孩子。
  • 若根节点不是叶子节点,则至少有2个孩子
  • 中间节点(除了根节点和叶子节点)至少有k-1个元素和k个孩子,其中 Ceil(m/2)<=k<=m,ceil代表向上取整, 例如ceil(2.5)=3。
  • 非叶子节点包含的元素左边指针指向的值不大于它,右边指针指向的值不小于它
  • 所有叶子节点都在同一层

下图展示的是一颗度为3的数据key记录为(1、3、5、6、8、9、10、14、15、16)的B树:

mysql 删除索引后的索引长度 mysql删除数据会重建索引_db2 删除索引

而对于B+树,我们首先定义一条记录为一个二元组[key, data] , key为记录的键值,data为记录中键值对应的数据。那么B+Tree相对于B-Tree有几点不同:

  • 非叶子节点只存储键值信息。
  • 所有叶子节点之间都有一个链指针。
  • 数据记录都存放在叶子节点中

如下图所示,展示的是一个同样度为3的数据key记录为(1、3、5、6、8、9、10、14、15、16)的B+树:

mysql 删除索引后的索引长度 mysql删除数据会重建索引_db2 删除索引_02

为什么使用B+树作为索引的数据结构
一般来说,索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储的磁盘上。这样的话,索引查找过程中就要产生磁盘I/O消耗,相对于内存存取,I/O存取的消耗要高几个数量级, 如下图所示,磁盘IO相对于内存操作是非常高昂的操作。

mysql 删除索引后的索引长度 mysql删除数据会重建索引_mysql 大量数据 更改索引_03

所以评价一个数据结构作为索引的优劣最重要的指标就是在查找过程中磁盘I/O操作次数的渐进复杂度。换句话说,索引的结构组织要尽量减少查找过程中磁盘I/O的存取次数。

mysql 删除索引后的索引长度 mysql删除数据会重建索引_mysql 删除索引后的索引长度_04

对于数据库b+树构建的索引,如上图所示,假设每个节点存在一个磁盘块中,如上图蓝色方框所示。如果要查找key为6的数据,首先把9所在的磁盘块读入内存中,发生一次磁盘IO,在内存中用二分查找确定6在根节点key值9的左边,通过根节点指针P1找到磁盘块2的地址,将其加载到内存,再发生一次磁盘IO,又因为6是大于等于6的,锁定磁盘块2的P2指针,通过指针加载磁盘块6到内存,发生第3次磁盘IO,同时内存中做二分查找找到6,结束查询,总计3次IO。以上只是简单描述如何通过索引高效快速地定位到数据记录的基本原理。实际上具体到真实的数据库页结构比较复杂的,具体可参考(https://zhuanlan.zhihu.com/p/66352669)。现实中MySQL的B+索引树的度一般在1000以上,在大多数情况下索引树的高度为2-3, 而高度为4的一颗满B+树理论上就可存储1000的3次方十亿级的数据。也就是只需要数次磁盘IO,便可以在百万千万甚至亿级的数据结构中找到我们需要的数据记录,因此利用B+树作为索引的数据结构是非常高效的。