面试过程中对于Mysql的考察,索引可以说是必考的,在开发过程中,我们也有可能跟索引打交道,开发过程中我们可能会遇到这种情况,一个sql执行很慢,公司DBA可能会让你优化一下sql语句,我们最直观的想法大概都是加索引吧?为什么加索引就变快了?怎么去加索引,什么时候适合加索引,索引什么会失效,这些也是面试官常常考察的点,接下来跟着fly一起我们一起研究一下索引相关的一些东西吧。
查看MySQL官方文档对索引的定义是这样的,索引(index)是帮助Mysql高效获取数据的数据结构,数据结构这个东西听起来就很高大上了,现在心里我们先有个定义,稍后一起研究下是这个数据结构是什么。
数据库主要是用来做数据的存储和查询的,我们大学的时候查询数据常见的一些数据结构如下
Hash:Hash是一种key-value的键值对,根据key取value
数组:有序数组,在等值查询和范围查询场景中的性能就都非常优秀,插入数据差点意思
树:能想到的是二叉树,红黑树,b-tree(InnoDB存储引擎用的就是这个玩意)
上面这么多数据结构,b-Tree树为啥万千宠爱于一身得到Mysql的选择,接下来我们分析一波
如果我们将二叉树当做Mysql底层的数据结构,我们看一下会有什么问题,如图所示现在比如我们想插入数据1,2,3,4,5如果使用二叉树的话,我们会发现最终的数据结构是一个斜树。现在我们想查询5,这个时候我们会从1开始一直遍历到5,这其实就是二叉树退化链表了嘛,而且树的高度为5,我们知道索引是放在内存中的,索引我们需要从磁盘中读取,我们查个5需要从1~5遍历,这样肯定是不行的,因为从磁盘中读数据需要寻址,就是磁道那些玩意,非常浪费时间,数据查询过程中,应该尽量避免读磁盘。
红黑树我们在JDK1.8听说个这个玩意,插入数据的时候会按照自己的规则维护一种平衡,现在我们看一下选择红黑树作为Mysql底层的数据结构会出现什么问题,如图所示我们插入1,2,3,4,5之后我们发现红黑树查3次就能查到,这样比二叉树好太多了,但是想一下,如果数据插入到1万呢,我们会发现还是那个问题,索引是放在内存上的,我们需要从磁盘读取的,我们需要降低树的高度,现在红黑树分两个叉,那么能不能分3个,4个,n个呢(更多的分叉其实就是b树系列)
每个节点包含键值和数据对象存放的地址指针
索引元素不会重复,节点的值都不相同
在B树上查找数据的流程是这样的,将根节点加载内存中,如图所示根节点上存在的很多有序的元素比如k1,k5,k10,载入内存中之后去查找响应的关键字,如果能查到,则查找成功返回,否则也一定能够确定要查找的关键字位于ki~ki+1之间,这个时候就会取出下一层的节点继续查找,直到到达叶子节点看是否能查到,因为叶子节点有data值,查找之后就能直接返回
Q:Mysql节点中一次能够存多少元素?
A:Mysql默认节点大小为16384,大约16K,实验的时候可以通过 **show global status like ‘Innodb_page_size’**查找相应默认值。
B+树是一种B-tree的变种,Mysql的索引选择的就是这个东西,有以下这几个特性
Q:为甚非叶子节点存储的是冗余元素而不是像B数那种存data元素?
A:把date数据去掉之后这样非叶子节点就能够存储更多的数据了,这样树就叉分的更多,对应的树肯定变的越低,磁盘I/O次数肯定变少。
在B+树上查找过程是这样的,有两种数据查找方式
索引主要有这些,唯一/非唯一索引,聚集索引/非聚集索引,组合索引
聚集/非聚集索引都采用了B+树实现方式, 数据库我们现在有一张用户表,通过读这个我们谈谈他两个的各自的特点:
如上图所示,聚集索引的主键叶子节点data保留的是完整的数据结构,数据和索引是在一块的,我们通过主键查找相应的记录之后能够直接返回记录的值。非主键索引叶子节点存储的是对应的主键,我们需要进行二次回表去主键B+树上执行一次查询操作。我们想下这个点有什么好处和坏处。
如上图所示,非聚集索引的索引文件只保存了数据记录的地址,索引上的顺序和物理上存储的顺序完全没有关联,而且主键索引和非主键上结构没有什么区别,都存的是地址,遍历的时候都是遍历到叶子节点取出地址,然后去相应地址上找出对应的值。这样做的好处我们想一下为什么,到时候好给面试官battle,好处有这两点
Mysql使用InnoDB创建表的时候,推荐使用整形的自增主键?为什么这样干,我们根据上面的自身点琢磨一下原因
原因是因为InnoDB会将数据和主键索引通过B+树来进行组织,所以我们创建表的时候通常使用一个自增的整形id,如果没有指定,Mysql会默认生成自增的rowid,这样新增加数据的时候,避免非单调的主键插入B+树为了维护相关特性进行分裂调整。数据会增加到当前数据页的后续位置。
优点
缺点
尽量选择区分度比较高的列建立索引,这里有个考点可能面试官问你为啥性别列为啥不能建立索引
频繁查询的列适合建立索引
遇到联合索引时候想一下最左匹配原则(下一章将具体讲解联合索引和最左匹配原则是啥,小伙伴对这个名字有个印象)
like模糊查询时候,%在前面的时候才会用到索引,另外两个情况都会让索引失效,具体例子如下
select * from USER us where name l like ‘公众号程序员fly%’ //name上有索引的话会使用到name上的索引 select * from USER us where name l like ‘%公众号程序员fly’ //name上有索引的话索引会失效转为全表扫描 select * from USER us where name l like ‘%公众号程序员fly%’ //name上有索引的话索引会失效转为全表扫描