文章目录

  • 什么是索引
  • 索引的存储结构
  • 如果使用有序数组
  • 如果使用单链表
  • 如果使用二分查找树(Binary Search Tree)
  • 平衡二叉树(AVL树)
  • 多路平衡查找树(B Trees)
  • 加强版多路平衡树(B+ Trees)
  • 简单了解HASH索引



前言:首先推荐一个数据结构可视化的网站:

https://www.cs.usfca.edu/~galles/visualization/Algorithms.html,本文不做过深的数据结构剖析,但是要简单了解一些数据结构的特性和概念。


了解索引的存储结构前,我们必须要先了解一些索引的基本概念。

什么是索引

索引:就是数据库管理系统中一个排序的数据结构,协助快速查询和更新表中数据。注意索引是放在磁盘上的
建立索引的方式:
1.建表的时候就创建
2.建完表后续想添加索引:alter table 表名 add index 索引名(字段名);
索引的类型:
1.normal:普通索引,非唯一的索引没有任何限制
2.unique:唯一索引,要求字段的值不能重复。(primary key主键索引,特殊的唯一索引,主键索引所在的列字段必须NOT NULL)
3.full Text:全文索引,如果要在一个大文本里匹配一个字符那么就可以创建一个全文索引。char、varchar、text这些类型才能创建全文索引,匹配语法:select * from 表名 where match(字段名) against(‘要匹配的字符’ in natural language mode);

索引的存储结构

我们都知道mysql中的索引有BTREE和HASH,而最常使用的就是BTREE。那么问题来了,为什么mysql当初的设计者要选择使用B树呢?

如果使用有序数组

我们知道数组有下标,像’=’,’>’,’<'这些查询效率会很高,但是,更新索引时就会出现挪动大量数据,改变数据下标,所以这并不适合作为mysql的存储结构。

如果使用单链表

针对上边问题,我们会先想到使用链表来解决更新问题,因为链表记录的有上个节点和下个节点的地址。但是看,插入和更新快了,他的查询效率大大减少,因为单链表不支持二分查询,所以说查询效率是很低的。那么有没有使用二分查找的链表呢?

如果使用二分查找树(Binary Search Tree)

二分查找树简称BST
特点:左子树的值都要小于父节点,右子树的值都要大于父节点。
缺点:如图所示,如果是有序的插入,那么BST树就会变成一个线性的链表(斜树,不平衡树),深度会很大。导致查询会很慢。所以也并不适合mysql的索引结构

innodb mysql 索引磁盘存储 mysql索引存储结构深入理解_二叉树

平衡二叉树(AVL树)

AVL也就是发明者的名字简写。

特点:基于二叉树,但左右子树的深度差得绝对值不超过1。如果右子树的深度和左子树的深度绝对值超过1,就会发生左旋(反之右旋),如下图:

innodb mysql 索引磁盘存储 mysql索引存储结构深入理解_二叉树_02


缺点:如果mysql采用这种方式存储索引,那么我们看下图存储示例:

innodb mysql 索引磁盘存储 mysql索引存储结构深入理解_数据库_03


假设我们要找37这条数据,我们去索引树上找,第一次拿到磁盘块1之后,要到server层来比较发现我们要找的数据比他大,就到右子树上找下个磁盘块,继续比较发现又小了,就继续到左子树找下个磁盘块。才拿到所需数据。

我们要知道,我们每次访问树节点的时候就是和磁盘的一次IO,将磁盘数据加载进内存。前边文章说过,在InnoDB中,IO操作的最小单位是页(page),默认是16kb。但是,如上图,一个节点只存储了那么点东西,是远远不够16kb的(16384个字节),所以说,使用AVL树每次IO都会浪费大量的空间,而且放的节点越多,IO次数也就越多,浪费的空间也就越大,所需时间也越多

比如上图中,要查找37这条数据,就要3次IO,如果有成千上万条数据呢,IO时间是无法估量的。
思考一下如何解决这一问题呢?我们可以让每个节点存储更多的数据,可以让二叉变成多叉(“叉数”也就是“路数”也称为“度”) ,这样可以让树的深度减少,IO次数也就越少,查询速度也就越快。

多路平衡查找树(B Trees)

我们来看,和上图同样的数据,在B树中要找37这条数据,如下图,只需要两次IO就可以了。数据量越大效果也就越明显。

innodb mysql 索引磁盘存储 mysql索引存储结构深入理解_数据库_04


那么这个B树是如何实现一个节点存储多个数据并且还保持平衡的呢?

分裂和合并:假如路数是3,也就是一个节点只能放两个数据,如果要插入第三个数据即路数即将超过3,将会产生分裂(反之合并)。如下图:

innodb mysql 索引磁盘存储 mysql索引存储结构深入理解_mysql_05


mysql中索引用的B树,并不是该B树,而是用的增强版的B+树,接下来我们了解一下,什么是B+树。

加强版多路平衡树(B+ Trees)

特点:和B树不同的是

1.B+树的节点上有几个数据,就有几路。

2.每个父节点的元素都会出现在子节点上,是子节点的最大或最小元素。

3.只有叶子节点才存储数据,并且每个叶子节点都有指向下一个节点的指针,形成一个有序链表。

innodb mysql 索引磁盘存储 mysql索引存储结构深入理解_数据库_06


我们来看一看B+树 有多强大:

假设存储bigint类型(8bytes),InnoDB中的指针大小为6bytes,所以这样的一个索引就是14个字节,每个节点16kb(16384个字节),那么一个节点就可以存放16384/14=1170路。那么子节点就可以存放11701170=1368900个索引也就有1368900路。那么假设一条数据1k,一个叶子节点16k可以存放16条记录,那么1368900路的叶子节点共可以存放136890016=21902400条记录,也就是两千多万条记录,树的深度只有2,查找数据只需三次IO。

不仅如此,B+树叶子节点还是一个有序的链表,如果我们进行范围的查找,如where id> 18 and id < 30,这种的条件查询,如果是B树他每次都会在根节点开始遍历查找,而B+树一次查找就可以沿着叶子节点的链表指针检索出所需数据。

B+树的优势:
1.单一节点存储更多的元素,使得查询的IO次数更少。
2.所有查询都要查找到叶子节点,查询性能稳定。
3.所有叶子节点形成有序链表,便于范围查询。

简单了解HASH索引

因为hash索引用的并不多,简单了解下:
hash方式在我们的索引里面去存储了键值和映射关系,会根据索引的字段去生成hash码和指针,指针指向数据,他的时间复杂度是永恒不变的O(1),查询速度很快。
不足之处:
1.生成hash码是无序的
2.只能做等值的查询,因为它要根据键计算出hash码,所以只能是根据key去查value这种形式
3.如果字段有很多重复的值,就会产生大量的hash冲突。
所以一般不会使用hash方式作为索引的存储结构