一、为什么要建立索引? 索引是帮助MySQL高效获取数据的排好序的数据结构(本质是一种优化查询的数据结构)索引存储在文件里索引结构(索引底层的数据结构) 二叉树红黑树HashB-树
存在表Test,表的字段分别为:Col 1和Col 2,为该表的Col 2 字段添加索引。为了方便理解,假设索引底层用的数据结构是二叉搜索树,则如下图:
我们都知道,MySQL数据库中的表中的数据是存储在磁盘上的。即该Test表的数据是存储在磁盘上的。如果我们有SQL语句:
SELECT Col1, Col2 FROM Test WHERE Col2 = 89;
现在要查找 Col 2 = 89 这条记录。CPU必须先去磁盘查找这条记录,找到之后加载到内存,再对数据进行处理。这个过程最耗时间的就是磁盘I/O(涉及到磁盘的旋转时间(速度较快)、磁头的寻道时间(速度慢、费时))。
如果我们不借助任何索引结构帮助我们快速定位数据的话,我们查找Col 2 = 89 这条记录,就要逐行去查找、去比较。从Col 2 = 34 开始,进行比较,发现不是,继续下一行。。。我们当前的Test表只有不到10行数据,但如果表很大的话,有上千万条数据,就意味着要做很多很多次磁盘I/O才能找到。速度是很慢的。
所以,这就是我们为什么要建索引,目的就是为了减少磁盘I/O的次数 ,加快查询速率。
二、索引如何工作?
上图中的Test表中,对字段Col 2 添加了索引,就相当于在硬盘上为Col 2维护了一个索引的数据结构,即这个二叉搜索树。二叉搜索树的每个结点存储的是(K,V)结构,key 是Col 2,value 是该 key 所在行的文件指针(地址)。比如:该二叉搜索树的根节点就是:(34,0×07)。
现在对 Col 2 添加了索引,这时再去查找 Col 2 = 89 这条记录的时候会先去查找该二叉搜索树(二叉树的遍历查找)。
读 34 到内存,89>34;
读 89 到内存,89 == 89;//找到了
找到之后就根据当前结点的value快速定位到要查找的记录对于的地址。我们可以发现,只需要查找两次就可以定位到记录的地址,查询速度就提高了。
三、MySQL中意的索引结构是B+树
但其实,MySQL底层索引用的数据结构是B+树。不过大体思路是一样的。那么,为啥不用二叉搜索树、AVL树、红黑树这些数据结构呢?
3.1 二叉搜索树的局限性
假设现在Col 2属性的值为(10,14,15,25,58),那么最终形成的二叉搜索树的结构是这样的:
我们发现,二叉搜索树出现了单边增长的情况,在这种情况下,二叉搜索树退化成了线性结构,和顺序查找(不建立索引)的效率差不多。因此要想最大性能的构造一个二叉搜索树,需要这个二叉搜索树是平衡的。也就是努力减少每个结点的左子树和右子树之间的高度差。这时就出现了AVL树。
3.2 AVL树
AVL树是带有平衡条件的二叉搜索树。所有结点的左右子树的高度差不超过1。同样对于(10,14,15,25,58),构造出来的AVL树的结构是这样的:
3.3 红黑树
根据红黑树的特点,构造出来是这样的:
这两种树结构相对普通的二叉搜索树,优化了一些,那么到底为什么不用AVL树、红黑树呢?:
1)这两种结构在插入数据之后,一般要调整树的结构来实现平衡,是比较耗性能的;
2)最主要的原因还是:二叉树查找的效率跟树的高度有关。每次查找都是一次磁盘I/O。在对上千万的数据进行查找时,这两种结构的高度还是太高了,影响查找效率。
3.4 B-树
为了减少树的高度,那我们就可以把树设计的“矮胖”一些。这时就能想到B-树。它类似普通的二叉查找树,不同的一点是B-树允许每个结点有更多的子结点。
优点:
一个结点里有多个元素,并且是非递减排列的;所有叶节点具有相同的深度,等于树高。
缺点:
一个结点中存放多少元素比较合适;范围查找时需要回溯结点;3.5 B+树
B+树和B树的区别就是:B+树的非叶子结点只包含导航信息,不包含实际的值。所有的叶子结点相连,便于区间遍历和查找。
所以最终MySQL索引用的就是B+树。