学习MySql索引的数据结构,只需这一篇就够了

什么是索引呢?

百度百科上的解释为: 索引是对数据库表中一列或多列的值进行排序的一种结构,使用索引可快速访问数据库表中的特定信息。

简单来说:字典目录就是整个字典的索引,也就相当于目录,字典目录的作用是快速定位某一个汉字,而索引的作用是快速定位所需数据
在这里插入图片描述

如何创建索引呢?

创建索引需要两个条件,这就是:我要给谁–以什么实现方式–创建什么类型的索引
1. 给谁:就是给那个字段,这里可以是一个字段,也可以是多个字段;
2. 实现方式:就是索引的数据结构,可以是BTREE、HASH;
3. 类型:就是索引的类型,innoDB中一共支持四种索引类型,分别是普通索引、唯一索引、主键索引、全文索引。

创建索引的字段:可以是一个字段,也可以是多个字段,在多个字段上使用时需要满足最左匹配原则。

索引方式:

  1. BTREE:是 MySQL 默认的索引方式 。
  2. HASH:以 KV 的形式检索数据,它会根据索引字段生成哈希码和指针,指针指向数据。【相比于BTREE结构,HASH中的数据不能按照排序来存储,也不支持范围查询】

索引的类型:

  1. 普通索引(Normal):也叫非唯一索引,没有任何限制。
  2. 唯一索引(Unique):唯一索引要求索引所在的列不能重复。
  3. 主键索引(Primary):是特殊的唯一索引,相比于唯一索引增加了一个限制条件,要求所在的列不能为null。
  4. 全文索引(Fulltext):用于搜索很长一篇文章的时候,效果最好。
    Fulltext的使用可参考:Fulltext的使用

为什么最终将树形索引的数据类型定义为B+树呢?

给你无序的数字,让你找出其中的某个数字,那只能一个个遍历了,对应的结构只能是HASH

但当这一串数字为有序的呢?大家第一反应一定是通过二分查找的方式检索,每次比较可以舍去一半的数据,那么对应到数据结构上应该使用什么数据结构来存储索引呢?答案可想而知,是平衡二叉树

平衡二叉树:从树根开始比较,每次可以舍去一半的数据,但同时也就说明,数据量每扩大一倍需要多比较一次。由于在当前比较之前,无法确定之后是走左子树还是走右子树,也就说明每一次比较伴随着一次数据读取。而IO是及其消耗性能的,那怎么办呢?大家可以想一下操作系统一次IO读取的数据大小是多少呢?对,是4k,而每次读取一个节点的节点大小远远不足4k,那么我们在每一个节点处多存储一些数据来减少磁盘的IO是不是更好一些呢?
平衡二叉树示例

多路平衡二叉树【B Tree】:每一个节点不再只存储一个数据,可以同时存储多个数据,尽量保证每一个节点的数据量的大小接近4k,这样就可以通过最少的IO次数来提高检索数据的效率。但是这只解决的等值比较的方式,那么范围查询如何通过索引来检索呢?可见B Tree也不是理想的数据结构,那么如何才能做到范围查询呢?线性有序的一串数字我们才能够更方便的进行范围查询,那么可不可以将BTree结构和线性有序的结构进行组合呢?
在这里插入图片描述
B+Tree:从B Tree中可以看出,数据大部分集中在叶子节点上,那我们将所有分支节点的数据复制一份到叶子节点上,那么从左向右看叶子节点就会发现,叶子节点存储了所有的数据,并且从左到右看上去是一个线性有序的序列,为了让程序也像人眼一样“”,那么上一个叶子节点的末尾存储下一个叶子节点的地址即可,也就构成了B+Tree的结构。
在这里插入图片描述
在理论上,三层B+Tree可以存储上百万条数据,也就是我们仅需要进行3次IO操作就可以快速定位到所需的数据。

有的人可能回想,那你每个节点存放这么多数据,我在每个叶子节点上不还是需要一个一个遍历比较吗,对比于没有索引的情况下,性能会有很大的提升吗?

对于这个问题,可以做一个假设:假设每个节点上存放一千条数据,树的高度一共为三层。由于每个节点有一千条数据,也就是说每个非叶子节点有一千个子节点,树的高度为3层的话一共可以储存1000 * 1000 * 1000=10w条数据,也就是说使用索引的情况下平均需要遍历5w次,而使用索引只需要遍历3 * 1000 =3000次,性能的提升是很明显的。

了解了索引数据结构的演变,那么MySQL中的数据结构是什么样子的呢?

MySQL中常用的存储引擎是MyISAM和InnoDB,我们在讨论两个常用存储引擎的索引结构时先看一下数据和索引的存放方式,我新建了两张表分别使用了MyISAM和InnoDB两个存储引擎,并建立了主键索引,数据以及索引的存储如图:在这里插入图片描述

.frm后缀文件定义了表的结构,MyISAM和InnoDB两者类似。

MyISAM:中除了.frm还有.MYD和.MYI

  1. .MYD(MyISAM Data),用于存放表数据
  2. .MYI(MyISAM Index),用于存放索引,索引的叶子节点存放的是数据的内存地址
    也就说明MyISAM索引和数据是两个独立的文件

InnoDB:中除了.frm还有.ibd
在InnoDB中数据的存储和索引的存储均在.ibd中,InnoDB中是以主键为索引来组织数据存储的,也就是所有数据都存在于主键的叶子节点上(如果没有显式创建主键,InnoDB会创建一个默认的主键索引),那么我如果给其他字段上创建普通索引是如何存储的呢?
如果给其他字段创建普通索引,子节点的key存放的是当前字段的值,而叶子节点的value存放的是该条数据主键的值(一般情况下为id)
在这里插入图片描述

总结有以下几点:

  1. 对于数据库索引来说:数据结构B Tree优于AVL Tree的主要原因是减少IO次数提升查询效率;B+Tree优于B Tree的主要原因是方便了范围查询。
  2. B+Tree中所有的数据都存放在叶子节点上,非叶子节点上的数据只用于比较;并且上一个叶子节点的末尾存放了下一个叶子节点起始位置的地址。
  3. MyISAM存储引擎数据和索引分属于两个不同文件;InnoDB中为同一个文件,并且通过主键来组织数据的存储,是真正的聚合索引。
  4. InnoDB中当通过非主键索引查询数据时,一般情况下是先定位到主键,在通过主键索引查询(当查询字段为当前非主键字段时,就不会也没必要去查询主键了)

推荐大家一个非常好用的查看不同数据结构存储过程的链接Data Structure Visualizations,可以直观的看到各种数据结构的存储过程。

▄█▀█●各位同仁,如果我的代码对你有帮助,请给我一个赞吧,为了下次方便找到,也可关注加收藏呀
如果有什么意见或建议,也可留言区讨论

  • 7
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值