(1)前序:
假设要搜索一个主键id对应的行,此时就应该先去顶层的索引页88里去找,通过二分查找的方式,很容易定位到应该去下层哪个索引页里继续找,比如定位到了下层索引页35里继续找,此时在索引页里也有一些索引条目,分别是下层各个索引页(20,28)和他们里面最小的主键值,此时在索引页35的索引条目里继续二分查找,很容易定位到到下层哪个索引页里继续找。可能从索引页35接着就找到下层的索引页28里去,这里存放了部分数据页页号 (比如数据页2和数据页8) 和每个数据页里最小的主键值。
此时就在这里继续二分查找,就可以定位到应该到哪个数据页里去找。接着比如进入了数据页2,里面就有一个页目录,存放了各行数据的主键值和行的实际物理位置,此时使用二分查找,就可以快速定位到你要搜索的主键值对应行的物理位置,然后直接从数据页2里找到那条数据即可,这就是基于索引结构查找主键的一个过程。
大家是否发现,其实最下层的索引页,都是会有指针引用数据页的,所以实际索引页之间跟数据页之间是有指针联系起来的。另外,索引页内部对于一个层级内的索引页,互相之间都是基于指针组成的双向链表,这个同一层级的索引页组成的双向链表,就跟数据页组成的双向链表是一样的。
(2)聚簇索引: 数据页包括 索引页
假设索引页和数据页综合起来看,他们都是连接在一起的,看起来就如同一颗完整的大的B+树一样,从根索引页88开始,一直到所有的数据页,其实组成了一颗巨大的B+树。在这颗B+树里,最底层最底层的一层就是数据页,数据页也就是B+树里的叶子节点。所以如果一颗大的B+树索引数据结构里,叶子节点就是数据页自己本身,那么此时就可以称这颗B+树索引为聚簇索引。
其实在innodb存储引擎里,在对数据增删改的时候,就是直接把数据页放在聚簇索引里的,数据就在聚簇索引里,聚簇索引就包含了数据,比如插入数据,那么就是在数据页里插入数据。
如果数据页进行了页分裂,此时会调整各个数据页内部的行数据,保证数据页内的主键值都是有顺序的,下一个数据页的所有主键值大于上一个数据页的所有主键值,同时在页分裂的时候会维护上层索引数据结构,上层索引页会维护索引条目,不同的数据页和最小主键值。
如果数据页越来越多,一个索引页放不下,此时就会再拉出新的索引页,同时再搞一个上层的索引页,上层索引页里存放的索引条目就是下层索引页页号和最小主键值。如果数据量越大,此时可能会多出更多的索引页层级来,不过,一般索引页里可以存放很多索引条目,所以通常而言,即使是亿级的大表,基本上大表里建的索引的层级也就三四层而已。
(3)总结:
这个聚簇索引默认是按照主键来组织的,所以在增删改数据的时候,一方面会更新数据,一方面会自动维护B+树结构的聚簇索引,给新增和更新索引页,这个聚簇索引也是默认建立的。
知识点1:聚簇索引只有最底层的索引页中存储了最小主键值和数据页的映射关系,上边基层的索引页只是存储了下层每个索引页中的最小主键值与索引页号的
对应关系。
知识点2:每一层的索引页组成一个双向链表,最后一层的叶子节点(数据页)也组成双向链表,说的没错。
知识点3:非叶子节点存储的是索引页页号+最小主键值id
知识点4:索引树的叶子节点存储数据页,其他非叶子节点存储的是下一层索引页页号及索引页里最小主键id
知识点5:按照B+树的存储特点,将索引页存放到B+树,索引页里有多个数据页和主键id,数据页根据主键id的大小排序,多个索引页按照B+树规则存放,
当同一层的索引页太多时,会抽象出更高一层的节点,这个节点也是存储索引的,这个索引页作为节点的特点比左边的子节点大,比右边的子节点小。
知识点6:主键索引索引页下叶子节点存储的是数据页的信息 非主键索引下叶子节点数据页存储的是索引字段的值+主键的值
知识点7:另外,B+树的阶数是等于键值的数量的,如果我们的B+树一个节点可以存储1000个键值,那么3层B+树可以存储1000×1000×1000=10亿个数据。
一般根节点是常驻内存的,所以一般我们查找10亿数据,只需要2次磁盘IO。
知识点8:聚簇索引:也叫簇类索引,是一种对磁盘上实际数据重新组织以按指定的一个或多个列的值排序, 由于聚簇索引的索引页指针指向数据页,所以使用
聚簇索引查找数据几乎总是比非聚簇类索引快。
知识点9:每张表只能建一个聚簇索引,并且建聚簇索引需要至少相当该表120%的附加空间,以存放该表的副本和索引中间页,数据页内部也是可以二分查找的,
索引页就是索引目录
为什么Mysql用B+树做索引而不用B-树或红黑树?
B+树只有叶节点存放数据,其余节点用来索引,而B-树是每个索引节点都会有Data域。所以从Mysql(Inoodb)的角度来看,B+树是用来充当索引的,
一般来说索引非常大,尤其是关系性数据库这种数据量大的索引能达到亿级别,所以为了减少内存的占用,索引也会被存储在磁盘上。
那么Mysql如何衡量查询效率呢?– 磁盘IO次数。 B-树/B+树 的特点就是每层节点数目非常多,层数很少,目的就是为了减少磁盘IO次数,
但是B-树的每个节点都有data域(指针),这无疑增大了节点大小,说白了增加了磁盘IO次数(磁盘IO一次读出的数据量大小是固定的,单个数据变大,
每次读出的就少,IO次数增多,一次IO多耗时),而B+树除了叶子节点其它节点并不存储数据,节点小,磁盘IO次数就少。这是优点之一。
另一个优点是: B+树所有的Data域在叶子节点,一般来说都会进行一个优化,就是将所有的叶子节点用指针串起来。这样遍历叶子节点就能获得全部数据,
这样就能进行区间访问啦。在数据库中基于范围的查询是非常频繁的,而B树不支持这样的遍历操作。
B树相对于红黑树的区别
AVL 树和红黑树基本都是存储在内存中才会使用的数据结构。在大规模数据存储的时候,红黑树往往出现由于树的深度过大而造成磁盘IO读写过于频繁,
进而导致效率低下的情况。为什么会出现这样的情况,我们知道要获取磁盘上数据,必须先通过磁盘移动臂移动到数据所在的柱面,然后找到指定盘面,
接着旋转盘面找到数据所在的磁道,最后对数据进行读写。磁盘IO代价主要花费在查找所需的柱面上,树的深度过大会造成磁盘IO频繁读写。
根据磁盘查找存取的次数往往由树的高度所决定,所以,只要我们通过某种较好的树结构减少树的结构尽量减少树的高度,B树可以有多个子女,从几十到上千,
可以降低树的高度。
数据库系统的设计者巧妙利用了磁盘预读原理,将一个节点的大小设为等于一个页,这样每个节点只需要一次I/O就可以完全载入。为了达到这个目的,
在实际实现B-Tree还需要使用如下技巧:每次新建节点时,直接申请一个页的空间,这样就保证一个节点物理上也存储在一个页里,
加之计算机存储分配都是按页对齐的,就实现了一个node只需一次I/O。