Mysql面试笔记汇总——索引结构基础篇

       在面试到mysql调优时,有一个常问的案例就是针对慢查询时你要怎么去优化,其中经常会提到的就是建索引,那么索引是什么?为什么建索引能提高mysql查询效率?如何去建立索引等问题,带着这些疑问进入本章主题。

一、索引是什么

       用官方的话来说,索引是一种单独的、物理的对数据库表中一列或多列的值进行排序的一种存储结构,它是某个表中一列或若干列值的集合和相应的指向表中物理标识这些值的数据页的逻辑指针清单。索引的作用相当于图书的目录,可以根据目录中的页码快速找到所需的内容。
       这里我引用一位网课的老师针对索引是什么总结出一句话:索引是一种排好序的数据结构。老师还特别强调排好序这个词是核心,下面将围绕这个词对索引结构展开详细说明。

(1)索引结构

       想要了解索引结构,我们可以从索引结构的演变历史开始了解。此处推荐大家使用一个数据可视化工具【https://www.cs.usfca.edu/~galles/visualization/Algorithms.html】,能够直观看到不同索引结构它的数据动态操作过程,包括插入,删除、查找等(注:此处插入的内容建议使用具备唯一性的数字进行操作更为清楚)。图示如下:
Mysql面试笔记汇总——索引结构基础篇_第1张图片

1)二叉树

解释:以非叶子结点为基础,判断是否大于该结点,如果成立,则往该结点的右侧插入,否则在左侧插入。结构图如下:
Mysql面试笔记汇总——索引结构基础篇_第2张图片
优点:结合数据结构和查询进行分析,该结构一定程度上减少I/O操作(I/O操作为一次数据库操作)。
缺点:针对递增索引的储存,最终会变为链表结构,随着的结点的增加,查询效率越低,如下图所示:
Mysql面试笔记汇总——索引结构基础篇_第3张图片

2)红黑树

解释:红黑树结构为平衡二叉树,当往红黑树结构中插入新元素时,右侧的高度比左侧高2层时,则进行自我平衡,结构图如下:
Mysql面试笔记汇总——索引结构基础篇_第4张图片
Mysql面试笔记汇总——索引结构基础篇_第5张图片
优点:在二叉树结构上进一步优化查询效率。该结构用于弥补二叉树的缺点,优化二叉树一直插入递增序列转为链表结构时带来的查询效率降低的问题。即当树结构达到一定高度时,数据结构会进行自我平衡,就不会形成列表结构。
缺点:当数据量处于百万或千万级别时,查询效率依然会很低,因为此时树的高度依然非常庞大,最坏情况下还是得查询很多次才能找到结果。

3)Hash表(现在依然存在Hash表结构)

结构图:与Java中的hash结构一致,将索引的key通过一次hash计算,找到对应的问题,最终将该索引对应记录的磁盘文件地址存储到链表中,最终再进行一次回表查询出完整的数据记录。
Mysql面试笔记汇总——索引结构基础篇_第6张图片
特点
①对索引的key进行一次hash计算就可以定位出数据存储的位置;
②很多时候hash索引要比B+数索引更高效;
缺点
①仅能满足“=”、“IN”,不支持范围查找;
②hash冲突的问题;

4)B-Tree

解释:B-Tree的结构是在红黑树结构上进行横向优化,即限定数的高度,在根节点层分配一定的空间,首先划分出一个排好序的结点空间,然后所有层的结点根据根结点层去一层一层划分,每层的各个结点也能横向划分多个结点。B-Tree又称为多路搜索树结构。
Mysql面试笔记汇总——索引结构基础篇_第7张图片
特点
①叶节点具有相同的高度,叶节点的指针为空;
②所有索引元素不重复;
③节点中的数据索引从左到右进行递增排序;
具体结构图如下:
Mysql面试笔记汇总——索引结构基础篇_第8张图片

5)B+Tree(B-Tree的优化结构)

特点
①非叶子节点不存储data,只存储索引(的冗余),可以放更多的索引;
②叶子节点包含所有索引字段;
③叶子节点用指针连接,提高区间访问的性能;(叶子节点采用双向链表的方式)

结构图
Mysql面试笔记汇总——索引结构基础篇_第9张图片
补充:B-tree和B+Tree的区别?
①B+Tree的非叶子节点都不会存储data数据(除索引以外的字段数据),主要是为了每一层空间能存取更多索引节点。
②B+Tree在叶子节点中维护了一个双向指针,便于范围查询。例如:通过B_Tree需要查询[15-78]之间的索引,左侧会先定位到左侧区间,但是在找到78时,索引需要重新从根结点开始往下找,最后才确定右侧范围在哪个索引区间中。而B+Tree只需要根据叶子节点的排序,往下找就行,不需要重新去根据根结点重新找一遍;

二、为什么建索引能提高mysql查询效率

       基于以上分析的索引结构,我们可以知道短浅了解到,索引是一种排好序的数据结构,排好序的数据对于我们人而言,它可以帮助我们快速定位到要查询的数据。而对于mysql底层的查询逻辑也一样,它是基于二分查进行查询,也能快速定位到要查询的数据,因为相对全表查询而言,建立索引查询能避免一些不必要的数据读取和比较,从而能大大地提高查询效率。
       此时也印证另外一个问题:为什么建立索引时,要尽可能地选择主键或具备唯一性的字段?在使用主键索引时为什么不推荐使用uuid而是自增主键?
解释:

(1)为什么建立索引时,要尽可能地选择主键或具备唯一性的字段?

       首先索引结构是需要针对每一条记录进行特定字段的排序而形成,如果该字段并不是自增字段或具备唯一性的字段,会导致索引结构在创建时,生成多个重复的根结点数据,随着数据量的增大,在mysql执行计划中,它很有可能会变成全表扫描(在mysql优化过程),因为它的结构将会变为如下图所示:
Mysql面试笔记汇总——索引结构基础篇_第10张图片
       此时再去查询001这条记录时,mysql就得扫描整个表的数据,确定所有数据都找得到为止。

(2)问题二:在使用主键索引时为什么不推荐使用uuid而是自增主键?

       结合上图也可以分析到,uuid符合了唯一性的特点,但不推荐使用主要有以下两方面:

1)uuid是字符串类型

解释: 由于uuid是字符串类型数据,它在比较的时候,可能需要一个一个字符去比较,或者是转为其他编码格式进行比较,从效率层面来说是偏低的。

2)uuid并不是按照顺序生成的,而是一串随机值

解释: 因为uuid每次生成的值都是唯一和无序的,在每次插入索引记录时,由于mysql底层都会自动维护好索引这个排好序的B+Tree结构,如果uuid生成的值刚好是递增顺序或者数据量比较少的情况,短期内使用可能没什么问题;后期数据量变很大,并且刚好插入的一条记录不是递增的时,那么B+tree会进行树的分裂、合并等情况(该步骤可以自行通过可视化工具演示),它可能会涉及到树结点复制等操作,从而引发严重的性能问题。

三、如何建立索引

       基于上述的分析,我们就能清晰地回答这个问题,索引字段可以最好是选择主键字段,并且是有序的,否则在某一些情况下,mysql查询依然会走全表扫描(跟mysql执行计划中的sql语句优化过程有关)。
       这里有一道现场面试题,自己也可以思考一下:
问题: 如果说建立索引能加快查询效率,那么我能不能为用户表中性别这个字段建立索引?如果不能,为什么?(如果有理解前面陈述的内容,这道问题其实很简单,此处不作回答)

四、总结

       本章主要是通过三个问题,简述索引结构是如何从二叉树结构最终演变为现在的B+Tree结构,并且结合一些案例问题,初步了解索引结构的作用原理及基础底层知识,最后初步认识索引的创建等,下章可能会介绍组合索引、聚簇索引和非聚簇索引等相关概念,当作是一个索引结构拓展篇。
       至此本章以写完,如果有大佬发现其中的描述有误或者不正确,欢迎在评论区提出批评和指正,谢谢。

你可能感兴趣的:(面试,mysql,面试,数据库)