简单理解:索引是一种排好序的数据结构
可以理解为索引是一种数据文件也是一种数据结构
1)索引是一种特殊的数据文件
①MyISAM存储引擎中:数据文件和索引文件是分开的,索引文件保存的是数据记录的地址。
②InnoDB存储引擎中:表数据本身就是按照B+Tree的存储的索引结构。在InnoDB查询数据文件时,.ibd文件就是数据+索引存储文件
2)索引是一种数据结构
①索引是一种独立的,物理的(真实存在的)数据结构,它是由一个表中的一个字段或者多个字段的值组成的集合。
我们要知道MySQL默认使用B+Tree结构管理索引
如上述此表无索引,查找语句需要从磁盘一条一条的对比,如果表特别大,io特别多。
改进:使用二叉查找树存储索引
二叉查找树的特点:
①任何节点的左子树的键值,一定小于当前节点
②任何节点的右子树的键值,一定大于当前节点
二叉树的优点:
上述查找语句,经历两次io即可查到。
二叉查找树的规律:
深度为1的,查找次数为1。深度为2的,查找次数为2。深度为n,查找次数为n。
上述二叉树平均查找次数:2.8次
二叉树的缺点:
在存储有序数据的时候,最终会形成一个链表,对于查找链表尾端的数据时,效率会很低。
既然二叉查找树不行,可以用平衡二叉树改进。
特点:
①在满足二叉查找树的条件下,还满足任意节点的两子树高度差最大为1。
优点:
在出现大于1的情况下,会使用LL旋转,或者LR旋转进行平衡,最终满足条件。这样就不会出现链表的情况。
缺点:
①每个节点最多有两个子节点,导致树高度过高,io次数特别多
②每个节点只保存一个关键字,每次操作获取的目标数据过少
结合1,2可以总结出,想要提升数据库性能的关键:减少磁盘io
①节点可以有多颗子树
②每个节点尽可能多存储一些数据
由此引出B-Tree,(B是balance)
1)什么是B-Tree
B-Tree是一个多路平衡查找树,允许一个节点存放多个数据 。(把瘦高的树变成矮胖的树)
2)B-Tree树的阶
B-Tree中所有节点的字数个数的最大值,称为B-Tree的阶。
上面这颗树所有节点,拥有子节点最多的节点有四个,都有三个子节点,所以上面这颗称为3阶B树。
3)m阶B-Tree满足以下条件:
①树的每个节点最多有m颗子树
②根节点至少有两颗子树(保持树的平衡)
③分支节点(除根节点,叶子节点外)至少有(m/2)颗子树。避免出现单颗子树的情况
④所有叶子节点都在同一层,并以升序排序
⑤有K颗子树的分支节点,则存在K-1个关键字,关键字按照递增顺序进行排序
4)B-Tree如何存储索引
B树首先定义一条记录为一个键值对(key,value)
①key为记录的键值,对应表中的主键值
②value是除主键外的一行记录
5)B树存储索引的特点
B树存储数据的特点:
①空白的块是指针,存放着子节点的地址信息。
②每个节点都存储多个索引值以及对应的value值(value是除主键外的一行记录)。也就是说索引值和value数据分布在整棵树中
③树节点中的多个索引值从左到右升序排序
6)B-Tree查找方式的特点:
①每个节点的元素,可以视为一次io读取,树的高度就表示了最多的io次数
②每个节点存取的元素个数越多,B树越矮,查找需要的io次数就越小
7)总结
B树的优点:
①B树可以在内部节点存储键值和相关的记录数据,若是把频繁访问的节点放在根节点,可以提高热点数据的查询效率
B树的缺点:
①上述优点也可称为缺点。因为每个节点不仅包含key值,还有value值,当value值特别大的时候,就会导致每个节点存储的key值减少,这就会导致B树的层数变高,io变多。
B树的使用场景:
主要应用于文件系统以及部分数据库索引,比如MongoDB。大多的关系型数据库都是使用B+Tree树结构进行管理索引。
聊B+Tree之前,我们先来讨论下B-Tree的不足,为什么mysql不用B-Tree管理索引。当然有一些前置的知识需要知道。
前置知识:
操作系统①操作系统从磁盘读取数据到内存是以磁盘块为基本单位的。
MYSQL②InnoDB存储引擎是按“页”来处理数据的,因此B-Tree/B+Tree的基础分配单位是页。InnoDB存储引擎中默认每个页的大小为16KB。
show variables like 'innodb_page_size';
③磁盘块(block)实际上并没有这么大,因此InnoDB每次申请磁盘空间时都会是若干地址连续磁盘块来达到页的大小16KB。
B-Tree的不足
①上述缺点,因为每个节点不仅包含key值,还有value值,如果每个节点都存储行数据是很占内存空间的,树的高度也变高,io也便多
②B树适用于随机访问,但是不适用于范围查询,因为范围查询通常需要顺序访问一系列的键值,不是随机访问。(究其原因是因为叶子节点不相连,顺序查询需要返回父节点,就像遍历整个树一样,io次数增特别多)
而B+Tree就是把B-tree的不足做了优化,更适合存储索引结构。
mysql的InnoDB存储引擎中,最小存储单元就是页(每个页默认大小是16KB)。而mysql的设计者将一颗B+Tree的节点大小就设置为了等于一个页(16KB),这样做的目的就是为了每个节点只需要一次io就能完整的载入一页数据。
mysql中B+Tree存储索引的特点:
①mysql除叶子节点外的节点的数据页,存放的是“关键字+指针“
②叶子节点的数据页,存放的是”关键字+数据“——单指聚簇索引
③B+Tree的根节点是保存在内存中的,子节点存储在磁盘中的。
④所有的节点按照索引键大小排序,构成一个双向链表,便于范围查询。
B+Tree的查找方式:
①和B-tree一样,从根节点通过指针实现随机查找,区别是B+Tree必须查找到叶子节点,才能获取到数据。
②到达叶子节点,可以进行顺序查找,在一个节点内部可以实现这般查找,在多个节点之间,因为是通过指针连接,所以要使用顺序查找。
例子:
随机查询就不举例了,和B-tree类似。
范围查询10~99的元素:
①自顶向下,查找到范围的下限10,通过链表的指针便利到元素99结束
我们发现对比B-tree的范围查询,B+tree的io次数更少,查询更简便。
B+Tree的优势:
B+Tree扫库和扫表能力更强。如果我们要根据索引去进行数据表的扫描,对B-Tree进行扫描,需要把整棵树遍历一遍,而B+TREE只需要遍历他的所有叶子节点即可(叶子节点之间有引用)。
B+Tree磁盘读写能力更强。他的根节点和支节点不保存数据区,所以根节点和支节点同样大小的情况下,保存的关键字要比B-Tree要多。所以,B+Tree读写一次磁盘加载的关键字比B-Tree更多。
B+Tree排序能力更强。上面的图中可以看出,B+Tree天然具有排序功能。B+Tree查询性能稳定。
B+Tree数据只保存在叶子节点,每次查询数据,查询IO次数一定是稳定的。当然这个每个人的理解都不同,因为在B-Tree如果根节点命中直接返回,确实效率更高。
一颗B+Tree可以存放多少数据:
首先一个高度2的B+Tree的记录数 = 根节点的指针数*单个叶子节点的记录数
1)根节点的指针书:int类型占4个字节,指针大小大概为6个字节
一个页可以存储16KB/(4b+6b)约=1600,一个节点最多存储1600个索引指针
2)叶子节点的记录树:假设value1KB,一页可以存储16行数据,16KB/1KB=16
3)高度为2可以存放1600*16约3万条数据,高度为3的可以1600*1600*16=4千万条数据
B+Tree高度一般为1~3层,就可以满足千万级别的数据存储。
下面将写《MySQL是怎样运行的:从根儿上理解MySQL》(小孩子)的阅读笔记,感兴趣的可以关注一下。