1 什么是索引?
索引是MySQL存储引擎用于快速查找记录的一种数据结构。
索引是一种特殊的数据文件:InnoDB 存储引擎中,表数据文件本身就是按照B+Tree组织的一个结构,这棵树的叶子节点保存的就是完整的数据记录,非叶子节点保存的是索引,在InnoDB中索引和数据都在.ibd文件。
索引是一种数据结构,它是根据某个表中一个字段或多个字段创建的一个集合。
1.1 为什么不用二叉查找树
二叉查找树的特点:
-
左子树的键值小于根的键值
-
右子树的键值大于根的键值
-
每个节点分别保存字段数据和一个指向对应数据记录的物理地址的指针
缺点:
- 二叉查找树会退化成单向链表
1.2 平衡二叉树
平衡二叉树可以通过叶子节点的自动旋转来进行调整,保证树的基本平衡。
平衡二叉树在满足二叉搜索树的条件下,还满足了任何节点的两个子树的高度差最大为1。
优点:
-
叶子节点的层级变少
-
形态上更平衡
-
查询效率提升
缺点:
-
一个节点最多分裂出两个子节点,树的高度太高,导致IO次数过多
-
节点中只保存了一个关键字,保存的内容太少
1.3 B-Tree
B-Tree是一种平衡的多路查找树,B树允许一个节点存放多个数据(把瘦高的树变得矮胖)。
B-Tree中所有的节点的子树最大的值成为B-Tree的阶,用m表示。必须满足以下条件:
-
树中每个节点,最多有m棵子树,存储最多m-1个关键值。
-
根节点至少有两棵子树。
-
分支节点至少有 m/2 棵子树。
-
所有叶子节点在同一层,并且以升序排序。
-
同一层的分支节点以关键字的升序排序。
特点:
-
索引值和data数据分布在整颗树中
-
每个节点可以存放多个索引值以及对应的数据
-
树节点中多个索引值从左到右升序排列。
-
B-Tree的每个节点元素,可以视为一次IO读取,树的高度表示最多的IO次数。
优点:
- 节点既存储索引也存储数据,因此如果将频繁访问的数据放在根节点的附近,就会大大提高热数据查询的效率。
缺点:
- 当data数据比较大的时候,就会导致每个节点存储的key变少。
1.4 B+Tree
B树存在的问题:
-
层数可能会很高
-
适合随机访问,不适合顺序查找
B+Tree特点:
-
每个分支节点至多有m棵子树。
-
根节点或者没有子树,或者至少两棵子树。
-
除了根节点外,其他每个分支节点至少有【m/2】棵子树,即至少有两棵子树。
-
有n棵子树的节点,恰好有n个关键字。子树的个数与该节点的关键字个数相同。(注意:B-Tree是n个关键字,n+1棵子树)。
-
所有叶子节点包含全部关键字及指向相应记录的指针,而且叶子节点按关键字大小,自小而大顺序链接。并将所有叶子节点链接起来。
-
所有分支节点(可以看做是索引的索引)中仅包含它的各个子节点(也就是下级索引的索引块)中最大关键字及指向子节点的指针。
-
B+树当中,只有叶子节点保存数据,其余中间节点仅仅是索引,没有任何数据关联。
2 B+树对比B树有什么优点?
从MySQL数据页的角度:
B+Tree的节点的大小为一个页(16KB),目的是每个节点只需要一次IO就可以完全载入。
-
分支节点的数据页,存放的是“关键字+指针”,可以看作是索引的索引
-
叶子节点的数据页,存放的是“全部的关键字+全部记录”,这是单指聚簇索引。
-
B+Tree的根节点是保存在内存中,子节点才是存储在磁盘中的。
-
所有节点按照索引键值的大小排序,构成双向的链表。
B+Tree的查找特点:
-
通过指针可以实现随机查找,从根节点开始
-
根据叶子节点进行顺序查找,在一个节点的内部是可以实现折半查找的但是如果在多个节点之间,因为是通过指针连接的,所以就要使用顺序查找。
B+Tree的优势:
-
B+Tree中间节点没有数据,所以同样大小的磁盘页,B+Tree可以容纳更多的节点元素(就是保存更多的索引),在相同数量的情况下,B+Tree比B Tree更加的矮胖,因此查询的IO次数更少
-
B+Tree的查询效率更加稳定,B+Tree的查询必须要达到叶子节点,B Tree最好的情况是在根节点,最坏的情况是在叶子节点,因此查询效率不稳定。
-
B+Tree扫库和扫表的能力更强,如果要根据索引进行数据表的扫描,对B-Tree进行扫描要把整棵树遍历一遍,而B+Tree只需要遍历他的所有叶子节点。
-
B+Tree的排序能力更强。
3 一颗B+Tree可以存放多少数据?
一个节点是一个页,16KB
-
计算根节点指针数:假设表的主键是int类型,占用的就是4个字节,指针的大小为6个字节,一个页大概可以存储:16384B/(4B+6B)
=1638,一个节点最多可以存储1638个索引指针。 -
计算叶子节点的能够存储的记录数:假设一行记录的数据大小1KB,那么一页就可以存储16行数据。16KB/1KB=16。
-
一颗高度为2的B+Tree可以存放的记录为:
163816=26208条数据记录,同样的方式就可以推算出高度3的B+Tree可以存放:16381638 *16=42938704,可以存放
4000多万条的数据。
- 所以InnoDB中B+Tree高度一般就是1-3层,就可以满足千万级别的数据的存储,在查找数据的时候一次页的查找代表一次IO