Mysql数据库索引面试题(程序员基础技能)


Posted in MySQL onMay 31, 2021

引言

索引是Mysql的一块硬骨头,但是对于程序猿来说又是十分重要的基础技能。在平常的项目开发中,它是重要的SQL优化手段。在求职面试中,它是面试官常常用来考察求职者数据库性能优化方面的重要考量。因此透彻的掌握索引原理,并能够将其运用到数据库查询实战是每个程序猿必备的能力。本文将从索引原理、索引设计原则方面阐述Mysql索引。相信阅读完本文之后,在Mysql索引查询数据理解这块完全可以征服阿里面试官。准备好了吗?我们发车了。

索引原理

在进行索引设计以及优化之前,我们先深入理解下索引的原理。因为所有的设计以及优化一定是建立在你对原理的透彻理解的基础上。

很多人都知道,在进行SQL查询时,同样一张表、同样的数据。不加索引以及加索引进行数据查询。两者差别很多。那么到底是为什么有这种差距。简单来说,如果把业务数据比作为一本字典的话,那么索引就是这本字典的目录。如果我让你查一个字,在你不使用目录查的时候,那只能一页一页的翻,运气不好的话可能要翻到最后一页才能查到想要的字,这就是传说中的全表扫描。但是如果我们通过目录来查找,那么可以很快定位字所在页,进而查找到对应的字。看到了吧,索引的威力就在于提高数据查询的效率。好了,现在我们对于索引有了感性的认识。那么我们接下来就深入了解下。

我们都知道在Mysql中索引的数据结构是B+树(这里不再说明B树、Hash索引等结构的优劣,不是本文的重点),那么我们就一步一步来看看,索引在磁盘中的B+树是怎么长成的。

1、数据页

在日常的项目开发中,我们的业务数据大部分都存在关系型数据中。那么数据库中各个表中的数据最终也都是存储在服务器的硬盘当中的。不知道大家有没有想过这个数据到底是怎么存储的呢?实际上Mysql数据库中我们每天都在使用的数据库表是对于人来理解的逻辑表。它实际在磁盘当中是通过一页页的数据页进行存储的。数据页是磁盘与内存交互的基本单位,MysqlInnodb存储引擎,实际通过buffer pool与磁盘中的数据页进行交互,而不是直接操作磁盘中的数据页。数据页的结构如下图所示:

Mysql数据库索引面试题(程序员基础技能)

同时相邻的数据页之间通过双向链表来维护数据页之间的相互引用。如下图所示,橙红色部分即为数据页,中间的小框框可以理解为一条条具体的数据。MysqlInnoDB存储引擎数据页大小是16KBMysqlInnodb存储引擎通过页号来唯一定位一个数据页,因此每个数据页都有自己的页号。通过上图可知,每个数据页都有都有对应的Page Header,在Page Header中保存了当前数据页的页号,以及其下一页的页号和上一页的页号。

Mysql数据库索引面试题(程序员基础技能)

相邻的数据之间通过指针进行互相引用,指针标注数据页的页号,每个数据页中存储了连续的一段数据,每个数据行中的记录头部存有下一行记录真实数据的地址偏移量,简单理解为拥有指针指向下一行数据的地址。因此在数据页的内部,实际是关于数据行的单向链表。这个单向链表是关于主键id的,从小到大进行排列。

Mysql数据库索引面试题(程序员基础技能)

从上述的数据页结构可知,每次进行数据插入时User Records区域就会变大,相应的的User Record区域就会减少。当User Record区域消耗完之后,就会发生页分裂,形成新的数据页。这里需要注意的是,如果我们使用的是Mysql中的自增主键,那么可以保证按照id的增长顺序进行数据行排列,但是如果主键是我们自己设置的并不是自增长的,那么有可能出现后面插入的数据的主键值小于前面数据的主键值,那么在进行页分裂的时候,Mysql会按照主键大小重新进行排列。此处不知道大家有没有疑问,为什么一定要按照主键大小进行排列呢?实际上和后续的数据查询有关系,数据页中的数据按照主键顺序进行排列是索引可以正常运行的基础。大致的过程如下图所示:

Mysql数据库索引面试题(程序员基础技能)

2、页目录

每个数据页都有自己的页目录上面页结构中的Page Directory,这个页目录的作用实际上就是用来进行数据行定位的。数据页中的数据实际上是按组分配的,页目录中的不同的槽位,其实是对应了数据页中的不同的分组,查询数据时,通过id找到对应的槽,再根据对应的槽来知道对应在数据页中的数据行分组,遍历数据行分组中的数据直到找到对应的数据。

Mysql数据库索引面试题(程序员基础技能)

3、索引原理分析

(1)索引基础

有了上面两节的数据页的基础知识之后,我们再来探讨索引原理就更加容易理解了。在没有索引时,数据查询都是进行全表扫描。遍历查询数据页中的每个数据行,再遍历所有的数据页,知道找到符合条件的数据项。因此查询效率十分的低下。那么应该怎么才能提供数据查询的效率呢?能不能像字典的目录一样,也搞个主键目录来进行数据页号的定位呢?答案是肯定的,Mysql实际也正是这么做的。Mysql通过主键目录实际就是传说中的主键索引,实现数据的查询优化。在主键目录中包含了两个重要元素,一个是数据页中最小的主键,另一个是当前数据页的页号。这样可以通过这个主键目录方面的进行数据查询。

举个栗子,如果此时想要查询主键id=5的数据,那么首先在主键目录中进行查找。此时发现主键id=5大于主键id=1,但是又小于id=8,那么就可以确定实际上数据实际是在页号为1的数据页中的。

当然在实际在Mysql中会有很多的数据页,因此对应的主键索引也会很多,那么此时就需要通过二分查找的方式进行数据页定位,再查找到对应的数据。

Mysql数据库索引面试题(程序员基础技能)

(2)索引页

如今当下,各个互联网公司迅猛发展,对应的业务量也是十分巨大。因此数据库中的数据量也是十分庞大的。表中的数据几百万、上千万可能很常见,按照上述的主键目录,那么就需要存储大量的主键与数据页号。即便是进行二分查找,其数据查询效率也是比较低的。

Mysql实际是将索引说句存储在索引页中的,当数据量比较大时候,对应的索引也会比较多,因此通过专门的索引页来存储索引数据。另外在这些索引页的上层又通过主键与索引页号来继续进行索引页的查询定位,因此我们得到如下的结构。其中的id号指的是对应最小的id号。

Mysql数据库索引面试题(程序员基础技能)

如果索引页中的数据越来越多,索引页同样会进行页分裂。这样索引页也就形成了不同的层级,索引页层、索引页、数据页这三个页数据就形成了我们说的B+树。下图就是索引的B+树结构,通过它完成数据查询效率远高于全表扫描。B+的叶子节点才会存储数据,下图是一种主键索引,也叫聚簇索引。其实我们可以看出来,它的根本思想就是分而治之的思想。数据量很大是吧,那我就把数据分成很多的数据页,数据页很多是吧,那我就通过索引页来组织数据页,索引页很多是吧,那就再通过索引页来索引。

Mysql数据库索引面试题(程序员基础技能)

我们再来看下,数据查询在B+树中的查询过程。举个栗子,如当前需要查询id为3的数据,那么将在索引页中判断应该走索引页为3的索引页。那么在索引页为3中继续判断id=1应该走索引页为1的索引页,在索引页中判断应该页号为1的数据页,在此数据页中遍历最终查询到对应的数据。

Mysql数据库索引面试题(程序员基础技能)

以上通过索引页与数据页组成的B+树就是聚簇索引,当然我们也可以通过其他字段来建立普通索引。知识普通索引会的叶子节点存储的是对应的主键id,而不是具体的数据,索引会存在回表的问题,即查询到对应的id之后,还需要根据id继续到聚簇索引中查询具体的数据,通过这样的操作才能查询到select *的所有数据。当然我们可以通过覆盖索引的方式避免这样的查询浪费。

总结

本文通过一步步图解的方式,为大家拆解MysqlInnoDB的索引原理,同时构建出对应的B+树索引结构。阐述了数据查询的具体过程。相信大家对于索引这块有了更加深刻的理解,后面会从实战的角度出发,分析下如何设计索引以及如何应对索引失效的问题。

MySQL 相关文章推荐
MySQL复制问题的三个参数分析
Apr 07 MySQL
MySQL中distinct与group by之间的性能进行比较
May 26 MySQL
MYSQL主从数据库同步备份配置的方法
May 26 MySQL
安装配置mysql及Navicat prenium的详细流程
Jun 10 MySQL
MySQL REVOKE实现删除用户权限
Jun 18 MySQL
Mysql实现简易版搜索引擎的示例代码
Aug 30 MySQL
防止web项目中的SQL注入
Dec 06 MySQL
MySQL 主从复制数据不一致的解决方法
Mar 18 MySQL
mysql中数据库覆盖导入的几种方式总结
Mar 25 MySQL
MySQL Server层四个日志的实现
Mar 31 MySQL
深入理解mysql事务隔离级别和存储引擎
Apr 12 MySQL
MySQL详细讲解变量variables的用法
Jun 21 MySQL
MySQL CHAR和VARCHAR该如何选择
May 31 #MySQL
带你学习MySQL执行计划
May 31 #MySQL
MySQL完整性约束的定义与实例教程
MySQL注入基础练习
解决Navicat for MySQL 连接 MySQL 报2005错误的问题
MYSQL(电话号码,身份证)数据脱敏的实现
May 28 #MySQL
MySql开发之自动同步表结构
You might like
再次研究下cache_lite
2007/02/14 PHP
PHP 中关于ord($str)>0x80的详细说明
2012/09/23 PHP
处理(php-cgi.exe - FastCGI 进程超过了配置的请求超时时限)的问题
2013/07/03 PHP
php生成excel列序号代码实例
2013/12/24 PHP
smarty自定义函数用法示例
2016/05/20 PHP
yii 框架实现按天,月,年,自定义时间段统计数据的方法分析
2020/04/04 PHP
javascript concat数组累加 示例
2009/09/03 Javascript
Asp.net下利用Jquery Ajax实现用户注册检测(验证用户名是否存)
2010/09/12 Javascript
基于jQuery实现下拉收缩(展开与折叠)特效
2012/12/25 Javascript
jquery 判断滚动条到达了底部和顶端的方法
2014/04/02 Javascript
js中setTimeout()与clearTimeout()用法实例浅析
2015/05/12 Javascript
jQuery实现MSN中文网滑动Tab菜单效果代码
2015/09/09 Javascript
JavaScript File分段上传
2016/03/10 Javascript
跨域资源共享 CORS 详解
2016/04/26 Javascript
JQuery的Pager分页器实现代码
2016/05/03 Javascript
jQuery手风琴的简单制作
2017/05/12 jQuery
JS实现json的序列化和反序列化功能示例
2017/06/13 Javascript
Vue Element 分组+多选+可搜索Select选择器实现示例
2018/07/23 Javascript
webpack之引入图片的实现及问题
2018/10/08 Javascript
Vue使用watch监听一个对象中的属性的实现方法
2019/05/10 Javascript
JavaScript对象原型链原理详解
2020/02/05 Javascript
vue前端和Django后端如何查询一定时间段内的数据
2021/02/28 Vue.js
Python实现拷贝多个文件到同一目录的方法
2016/09/19 Python
Python使用re模块正则提取字符串中括号内的内容示例
2018/06/01 Python
pycharm打开命令行或Terminal的方法
2019/01/16 Python
使用python 的matplotlib 画轨道实例
2020/01/19 Python
python+selenium+PhantomJS抓取网页动态加载内容
2020/02/25 Python
css3 transform导致子元素固定定位变成绝对定位的方法
2020/03/06 HTML / CSS
中国一家综合的外贸B2C电子商务网站:DealeXtreme(DX)
2020/03/10 全球购物
Why do we need Unit test
2013/01/03 面试题
在职人员函授期间自我评价分享
2013/11/08 职场文书
党员干部承诺书
2014/03/25 职场文书
校园文化艺术节宣传标语
2014/10/09 职场文书
寻找成龙观后感
2015/06/12 职场文书
贫困证明书范文
2015/06/16 职场文书
vue2实现provide inject传递响应式
2021/05/21 Vue.js