MySQL索引底层数据结构

1、何为索引?数据库

一、索引是帮助数据库高效获取数据的排好序数据结构数据结构

二、索引存储在文件中。性能

三、索引建多了会影响增删改效率。优化

(下面这张图为计算机组成原理内容,每查询一次索引节点,都会进行一次磁盘IO读取,即要寻道和旋转)spa

2、MySQL索引结构为何是B+树?指针

MySQL 建索引可以使用的数据结构有B+树Hash两种,可是Hash用得不多, 优势是能够快速定位到某一行,缺点是不能解决范围查询问题。blog

对于若是不须要使用范围查询、只须要精准查询的场景,可使用Hash索引方法,好比查电话号码。索引

再说说主流的索引方法B+树,先说下为何不用别的树结构,再说为何用B+树。内存

一、为何不用二叉树?字符串

若是碰到下面这种单边增加的极端状况,查找节点4和顺序查找没区别。(这种特殊状况的二叉树等同于链表,时间复杂度为O(n))

二、为何不用红黑树?

红黑树是一颗平衡二叉树,数据量大的时候,树的深度也很深,若是树的深度有20层,而查找的数据在叶子节点,就要进行20次IO操做,性能低。

三、为何不用B树?

B树的特色:

  • 叶子节点具备相同的深度
  • 叶子节点的指针为空
  • 叶子节点中的数据key从左到右递增排列

其实B树就是在横向作了文章,一个节点能够存储更多数据(大节点包含不少小节点),这样相对来讲,深度就会变浅。

提问:横向的节点怎么查,好比说查找上图中的节点77?

从磁盘中把大节点查找出来,把这个大节点加载进内存中,节点77其实是在内存中查找的,在内存中作的是随机访问,速度很快,跟磁盘的寻道和旋转相比的话,基本能够忽略不计。

提问:为何不可让B树横向的度无限增大,这样不就深度为1,查找不就更快了?(度的含义:节点的数据存储个数)

原本是想经过一次IO操做把一个大节点加载进内存,若是一个大节点的数据量太大的话, 则内存和硬盘一次交互没办法交换那么多数据,假设一次只能交换1页(4k)的数据(有上限,也有多是几十页,和计算机硬件有关),意味着CPU去硬盘上作一次IO操做只能取1页的数据,那么当一个大节点的数据量太大时,仍要进行屡次IO操做。所以,度是有上限的,MySQL会根据计算机硬件自动进行度的优化,一个大节点一般为1页空间。

四、为何使用B+树?(B+树是B树的变种,索引作了冗余,存了多份,可是不要紧,索引只占很小空间,好比下图中的15节点)

B+树的特色:

  • 非叶子节点不存储data,只存储key,能够增大度(相比B树,B+树的深度更浅)
  • 叶子节点不存储指针
  • 顺序访问指针,提升区间访问的性能(其实是双向指针)

提问:为何说B+树能够增大度?

由于非叶子节点只存储索引一个值,不存储data(B树会存储data),而大节点大小是肯定的,所以节点就能够存储更多的数据,即度能够变得更大。这样既保证度能够达到最大,又保证一个大节点经过一次IO操做能够加载进内存。(非叶子节点度更大,深度更浅,只有非叶子节点才影响查找次数,叶子节点是最后一次查找,对总的查找次数是没有影响的,所以把data所有移到了叶子节点)

提问:为何叶子节点之间还须要用指针?(一个大节点的尾节点和下一个大节点的头节点之间的指针链接)

方便范围查询。好比查找上图中key>18,若是没有指针会很是麻烦,必须从头开始查找,若是有指针,则能够直接遍历key>18的叶子节点(链表)。 

B+树索引的性能分析:

  • 通常使用磁盘I/O次数评价索引结构的优劣
  • 预读:磁盘通常会顺序向后读取必定长度的数据(页的整数倍)放入内存
  • 局部性原理:当一个数据被用到时,其附近的数据也一般会立马被使用
  • B+树的大节点大小设为等于一个页,每次新建大节点直接申请一个页的空间,这能保证一个大节点物理上也存储在一个页里,大节点载入只需一次IO操做
  • B+树的度d通常会超过100,所以高度h很是小(通常为3~5之间

3、MySQL底层是怎么用B+树来存储数据的?

MySQL有两种常见的存储引擎:InnoDB(默认)、MyISAM(用得少,在MySQL8.0中被废弃掉了),存储引擎范围是表级别的。

一、MyISAM索引实现(非汇集)

  • 索引文件和数据文件是分离的
  • 索引结构的叶子节点value存储的是文件指针。

.frm是表结构文件,.MYD是数据文件(MyISAM Data),.MYI是索引文件(MyISAM Index)。

MyISAM主键索引查找流程:先经过.MYI文件找到对应索引的文件指针,再根据文件指针去.MYD文件中定位对应的那行数据。

MyISAM普通索引查找流程:和主键索引查找流程一致。

 二、InnoDB索引实现(汇集)

  • 数据文件自己就是索引文件
  • 表数据文件自己就是按B+树组织的一个索引结构文件
  • 汇集索引的叶子节点包含了完整的数据记录
  • 表必须有主键,且推荐使用整型的自增主键
  • 普通索引结构叶子节点存储的是主键值

.frm是表结构文件,.ibd是数据和索引文件(InnoDB Data)

InnoDB主键索引查找流程:经过.ibd文件找到对应的索引,索引的value即为那行对应的完整数据。

InnoDB普通索引查找流程:经过.ibd文件找到对应的索引,索引的value即为那行对应的主键的值,再根据主键值去主键索引树中找到对应的行数据。

提问:汇集索引和非汇集索引的区别?

汇集索引:表中那行数据的索引和数据都合并在一块儿了。

非汇集索引:表中那行数据的索引和数据是分开存储的。

提问:为何InnoDB表必须有主键?

由于整个数据文件自己就是按照B+树组织的一个索引文件,因此必需要有主键(建InnoDB表时不指定主键,默认会从表字段中选一列做为惟一主键,若是不存在这种字段,则后台默认生成一个长整型主键字段,MyISAM能够没有)。

提问:为何推荐使用整型的自增主键?

提升查询性能。若是是使用UUID做为主键,第一,UUID长度很长,会浪费存储空间,第二,UUID是字符串类型,比较大小要查找ASCII码表,查找速度没有整型int查找速度快,第三,UUID是随机生成无序的字符串,当数据插入时,有很大可能会致使节点位置移动,还可能形成不少其余节点位置移动,简单来讲就是位置打乱了; 若是使用整型的自增主键,新插入的数据都会连续的插入到磁盘的物理空间。

提问:为何InnoDB普通索引结构叶子节点存储的是主键值?(一致性和节省存储空间)

若是普通索引的value也存数据,那么当往有主键索引和普通索引的表中插入数据时,索引结构中key对应的value要存储两份数据,增长维护成本。

单值索引:只有一个索引,如(id),size=1

联合索引:多个索引合起来做为一个联合索引,如(id,name),size>1(单值索引是联合索引size=1的特例)

提问:联合索引的底层数据结构长什么样?

先比较id,若是id相等,再比较name,若是name也相等,则再比较date。(索引最左前缀原理,后面索引优化随笔会讲解)

相关文章
相关标签/搜索