03-看透索引本质这一篇就够了

本来标题是“03-MySQL优化系列之后-看透索引本质,理清B-tree和B+tree”,但是发现居然是“零推荐”,其他技术含量一般的文章,反而推荐好几千,试试换换标题看看推荐量有没有变化。

我们常常听说,要提高数据库的查询速度,就要添加索引,可是细想以下三个问题,你是否能讲清楚?

1,索引究竟是什么?

2,为什么索引可以提高查询效率?

3,既然索引这么好,那么我所有的字段都加索引好了,这样不就世界都美好了吗?

搞清楚这三个问题,基本上你对索引的认识就差不多了,阅读完本文,相信你对三个问题会非常清晰。

下面,我们一一来探索交流。

1,什么是索引

你可能常见的说法是,索引是指一本书的目录,其实这是一种近似的说法,但不是十分准确。

确切来说,索引是存储引擎用于快速找到记录的一种数据结构,是对查询性能优化最有效的手段。

2,索引到底是一种什么样的数据结构?为什么可以提高查询效率?

MySQL索引的底层数据结构,主要有两种,一种是B+tree,一种是哈希。

3,那两种数据结构,我们究竟采用哪种?

其实从定位来说,哈希完胜B+tree,因为哈希的时间复杂度是O(1),但是我们的业务系统开发场景中,更多是这样的情况,比如where id>10或者where age>18等等,大家会发现,此类方式,更多是一种范围查找,而这个就是哈希的软肋,因为哈希的前后数据并没有顺序性,是采用散列的方式进行分布,所以哈希虽好,但是根据业务系统开发的需要,我们更多采用的是B+tree的数据结构。

你可能又听说过B-tree,那么B-tree和B+tree又有什么差异?下面从B+tree的演变历史来说起

4,B+tree的演变历史

4.1 演变路线图

二叉树---》平衡二叉树---》B-tree---》B+tree

下面,我们以同样存放进1-9的数据为例,来看他们有什么差异

4.2 二叉树

二叉树,是每个节点最多有两个子节点,是一种左中右的数据结构。

存放1-9之后的结构如下:

03-看透索引本质这一篇就够了

这就是二叉树可能会存在的问题,数据一边倒,而这样就发挥不了二叉树搜索的优势,于是就有了平衡二叉树

4.3 平衡二叉树

平衡二叉树,它要求左右两个子树的高度差不能超过1,并且左右子树都是一颗平衡二叉树。

跟二叉树的最大差别在于,会通过左旋转右旋转来保证整棵二叉树的平衡。

那么采用平衡二叉树,存储的数据结构如下:

03-看透索引本质这一篇就够了

那么平衡二叉树,看着已经挺完美了,又有什么问题?

随着数据量的增加,这颗平衡二叉树的深度也会递增,而在索引树进行查找时,随着深度的递增,跟IO交互的次数也会递增,那么性能也会下降,所以解决的办法在哪?

没错,就是在一样的数据量的情况下,减少数的深度。如何做到?

如果你想到了,真的很不错,就是将平衡二叉树变为多叉查找树,这就是我们要讲的B-tree

4.4 B-tree

采用B-tree结构,存储的数据应该是这样的,很明显,层次变少了,这样就减少了我们跟IO交互的次数

03-看透索引本质这一篇就够了

但是,这就完美了吗?

还是不够,我们再来认识B-tree的升级版B+tree

4.5 B+tree

B+tree,也称多路搜索树,他们最大的区别是,B+tree所有的数据都保存在叶子节点上,节点按照大小进行排序,结构图如下:

03-看透索引本质这一篇就够了

4.6 结论

所以,最终MySQL采用的是B+tree的数据结构,看完以上的分析,你应该已经清晰知道索引是一种什么样的数据结构,为什么可以提高搜索效率了。

4.7 衍生,聚集索引和非聚集索引

在MySQL里面,还存在,一个聚集索引和非聚集索引,他们都是指B+tree的一种具体表现,那么有什么区别?

4.7.1 聚集索引

MySQL无法主动创建聚集索引,InnoDB存储引擎会将我们的主键作为聚集索引。如果没有定义主键,则InnoDB会选择一个唯一的非空索引代替。如果没有这样的索引,则InnoDB会为该表生成一个rowid做为主键。

聚集索引的叶子节点存放表中所有的行数据信息,这样找到索引就找到了数据,而不用继续查询,这就是为什么以id主键查找数据,速度相比其他索引字段查找快的原因。

效果图如下:(偷了懒,我只是画了两个作为代表)

03-看透索引本质这一篇就够了

4.7.2 非聚集索引

我们创建的索引都属于非聚集索引,叶子节点只存放自身的键值和主键的值,叶子节点并不包含所在行的数据记录。

比如,我们为name创建了索引,那么它就是非聚集索引。如果我们的查询语句,是这样

select name from sys_user where name='feng';

那么,这个时候,使用的是覆盖索引,即索引树的数据就可以满足我们的查询需要。

而如果,这么写

select name,age,phone from sys_user where name='feng';

那么,由于非聚集索引本身没有包含行的数据,所以还需要根据自身保存的主键值,找到聚集索引树,然后再得到行数据,所以这种情况下,相比直接按主键查找效率会低。

下面,给大家留两个思考题:

1,索引的优点是提高查询效率,那么缺点是什么?

2,UUID具有唯一性的特点,那么是否合适作为主键?

希望对你有所帮助。

03-看透索引本质这一篇就够了


分享到:


相關文章: