Mysql索引原理

索引基本介绍

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

二叉树、红黑树、Hash表、B树等都可以作为索引。

  • 二叉树高度不可控,查询性能差;
  • 红黑树高度比二叉树小,但是也不可控,而且插入是有自旋问题,数据量大时性能比较差;
  • Hash表性能是最强的,但是无法支持区间范围查找,排序等功能;

Mysql 的索引使用B树的变种B+树来实现,并且对B+树做了点扩展。

B树

二叉树、红黑树这种数据结构,在大数据量的时候的时候,高度不可控,从而导致搜索慢。红黑树还有插入时的自旋问题,数据量大时插入慢。

我们希望在大数据量的时候,依然只需要访问很少次数就能查找到想要的元素。

对红黑树进行横向扩容,就形成了B树。

特点

  • 每个节点存储更多的元素,组成一个大节点,这样可以很大程度上减小树的高度。一个大节点是一个磁盘块
  • 所有索引元素不重复
  • 节点中的数据索引从左到右递增排列
  • 非叶子节点,前后会有一个指针,存储子节点的地址信息
  • 叶子节点具有相同的深度,叶子节点的指针为空

缺点:每个节点都会存储data数据,而一个节点的data数据量可能很大,innodb引擎,data里存储的是其他列的数据,占用的存储空间可能就比较大,Mysql推荐一个大节点总容量固定是16KB(通过参数 Innodo_page_size 设置,默认16KB),在大节点总容量固定的情况下,如果data比较大,那么这个大节点所能容纳的节点数量就会少,高度也就会增加。所以Mysql不会直接使用B树。

B+树

B+树是B树的一个变种。

特点

  • 非叶子节点不存储data,只存储索引,所以可以放更多的索引
  • 叶子节点包含所有索引字段
  • 叶子节点用单向指针连接,提高区间访问的性能

Mysql对B+树又进行了一些扩展,以支持更多的功能

  • 高度固定为3层
  • 每个大节点的存储空间限制是16KB,不管是叶子节点还是非叶子节点
  • 叶子节点的指针是双向的,而且最后的大节点还会跟第一个连接,以支持区间正序/倒序排序等功能。

下图来源于网络!

为什么大节点存储空间限制16KB?

以 InnoDB 主键索引为例:

主键 bigint 8B,下一个节点的指针 6B,一个大节点约包含 16KB / (8+6)B 约等于 1170 个索引元素,所以第三级的有 1170 * 1170 个大节点。

第三级的每个大节点也是每个16KB,假设每个data占1KB,那个一个大节点有16个元素,最终节点数量就是 1170 * 1170 * 16,约2000多万。

所以,千万级别的表,查找表里任意元素,也只要经过3次磁盘I/O。

InnoDB & MyISAM 引擎

最大区别

  • MyISAM引擎中,data存储的是索引所在行的磁盘文件指针
  • InnoDB引擎中,data存储的是索引所在行的其他所有字段数据

InnoDB索引实现

主键索引

表数据文件本身就是按B+树组织的一个索引结构文件

聚集索引(也叫聚簇索引):叶子节点包含完整的数据记录(就比如InnoDB的主键索引),索引跟表的数据放在一个文件里

InnoDB表必须有主键,如果没有,mysql找不到唯一的列,它会自动生成一个列

为什么主键最好是整形且自增?

整形:查找的时候会有大量的索引元素的比较,整形比较很快。UUID比较起来就远远慢于整形比较。而且UUIT占用的存储空间也比整形大。

自增:自增的情况下,新的节点都是往后面加,基本上不会出现元素分裂、再平衡的问题。如果不是自增,可能一个大节点16KB存储空间已经满了,想再往里面插入时,会导致一个节点分成两个节点,并且第二层会进行再平衡,效率会大大降低。

非主键索引

data存储的不是所有所在行的其他所有字段,而是索引所在行的主键!

需要遍历两棵树

为什么要这么设计?

  • 一致性:不需要所有索引全部建立好之后才能把数据才插入
  • 节省存储空间:完整的数据只保存一份

MyISAM索引实现

非聚集索引(也叫稀疏索引):索引和索引所在行的数据,在不同的文件中。索引在MYI文件中,数据在MYD文件中,分开存储。

下图来源于网络!

联合索引底层结构

联合索引的基本结构与主键索引是一样的,只不过它的索引键值为联合索引中所有列的值。

索引中的每个叶子节点,按照建立索引时列的顺序来递增排列的。例如上图中所用中有三列:(name,age,postion),那首先比较 name,name 小的排在前面。当name相同时,age小的排在前面,依次类推!

这个联合索引的结构,也决定了 Mysql 查询的时的一个规则:最左前缀原则

SELECT * FROM employees WHERE age = 26 AND position ='java开发';  // 不使用索引
SELECT * FROM employees WHERE position = 'java开发工程师';              // 不使用索引
SELECT * FROM employees WHERE name = 'lili';                                       // 能使用索引

联合索引的结构决定了,查询的时候按照建立索引字段的顺序逐个比较,所以如果没有第一列,那么无法定位数据,也就无法使用索引了。同理,如果只有第一列跟第三列,那么只能根据第一列来查找,第三列无法生效!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值