美文网首页
2020-09-07MySQL索引凭什么能让查询效率提高这么多?

2020-09-07MySQL索引凭什么能让查询效率提高这么多?

作者: 少荃_42a2 | 来源:发表于2020-09-07 15:12 被阅读0次

MySQL索引凭什么能让查询效率提高这么多?

 java后端 mysql数据库面试

发布于 今天 09:00

背景

我相信大家在数据库优化的时候都会说到索引,我也不例外,大家也基本上能对数据结构的优化回答个一二三,以及页缓存之类的都能扯上几句,但是有一次阿里P9的一个面试问我:你能从计算机层面开始说一下一个索引数据加载的流程么?(就是想让我聊IO)

我当场就去世了....因为计算机网络和操作系统的基础知识真的是我的盲区,不过后面我恶补了,废话不多说,我们就从计算机加载数据聊起,讲一下换个角度聊索引。

正文

MySQL的索引本质上是一种数据结构

让我们先来了解一下计算机的数据加载。

磁盘IO和预读:

先说一下磁盘IO,磁盘读取数据靠的是机械运动,每一次读取数据需要寻道、寻点、拷贝到内存三步操作。

寻道时间是磁臂移动到指定磁道所需要的时间,一般在5ms以下;

寻点是从磁道中找到数据存在的那个点,平均时间是半圈时间,如果是一个7200转/min的磁盘,寻点时间平均是600000/7200/2=4.17ms;

拷贝到内存的时间很快,和前面两个时间比起来可以忽略不计,所以一次IO的时间平均是在9ms左右。听起来很快,但数据库百万级别的数据过一遍就达到了9000s,显然就是灾难级别的了。

考虑到磁盘IO是非常高昂的操作,计算机操作系统做了预读的优化,当一次IO时,不光把当前磁盘地址的数据,而是把相邻的数据也都读取到内存缓冲区内,因为当计算机访问一个地址的数据的时候,与其相邻的数据也会很快被访问到。

每一次IO读取的数据我们称之为一页(page),具体一页有多大数据跟操作系统有关,一般为4k或8k,也就是我们读取一页内的数据时候,实际上才发生了一次IO。

(突然想到个我刚毕业被问过的问题,在64位的操作系统中,Java中的int类型占几个字节?最大是多少?为什么?)

那我们想要优化数据库查询,就要尽量减少磁盘的IO操作,所以就出现了索引。

索引是什么?

MySQL官方对索引的定义为:索引(Index)是帮助MySQL高效获取数据的数据结构。

MySQL中常用的索引在物理上分两类,B-树索引和哈希索引。

本次主要讲BTree索引。

BTree索引

BTree又叫多路平衡查找树,一颗m叉的BTree特性如下:

树中每个节点最多包含m个孩子。

除根节点与叶子节点外,每个节点至少有[ceil(m/2)]个孩子(ceil()为向上取整)。

若根节点不是叶子节点,则至少有两个孩子。

所有的叶子节点都在同一层。

每个非叶子节点由n个key与n+1个指针组成,其中[ceil(m/2)-1] <= n <= m-1 。

这是一个3叉(只是举例,真实会有很多叉)的BTree结构图,每一个方框块我们称之为一个磁盘块或者叫做一个block块,这是操作系统一次IO往内存中读的内容,一个块对应四个扇区,紫色代表的是磁盘块中的数据key,黄色代表的是数据data,蓝色代表的是指针p,指向下一个磁盘块的位置。

来模拟下查找key为29的data的过程:

1、根据根结点指针读取文件目录的根磁盘块1。【磁盘IO操作1次

2、磁盘块1存储17,35和三个指针数据。我们发现17<29<35,因此我们找到指针p2。

3、根据p2指针,我们定位并读取磁盘块3。【磁盘IO操作2次

4、磁盘块3存储26,30和三个指针数据。我们发现26<29<30,因此我们找到指针p2。

5、根据p2指针,我们定位并读取磁盘块8。【磁盘IO操作3次

6、磁盘块8中存储28,29。我们找到29,获取29所对应的数据data。

由此可见,BTree索引使每次磁盘I/O取到内存的数据都发挥了作用,从而提高了查询效率。

但是有没有什么可优化的地方呢?

我们从图上可以看到,每个节点中不仅包含数据的key值,还有data值。而每一个页的存储空间是有限的,如果data数据较大时将会导致每个节点(即一个页)能存储的key的数量很小,当存储的数据量很大时同样会导致B-Tree的深度较大,增大查询时的磁盘I/O次数,进而影响查询效率。

B+Tree索引

B+Tree是在B-Tree基础上的一种优化,使其更适合实现外存储索引结构。在B+Tree中,所有数据记录节点都是按照键值大小顺序存放在同一层的叶子节点上,而非叶子节点上只存储key值信息,这样可以大大加大每个节点存储的key值数量,降低B+Tree的高度。

B+Tree相对于B-Tree有几点不同:

非叶子节点只存储键值信息, 数据记录都存放在叶子节点中, 将上一节中的B-Tree优化,由于B+Tree的非叶子节点只存储键值信息,所以B+Tree的高度可以被压缩到特别的低。

具体的数据如下:

InnoDB存储引擎中页的大小为16KB,一般表的主键类型为INT(占用4个字节)或BIGINT(占用8个字节),指针类型也一般为4或8个字节,也就是说一个页(B+Tree中的一个节点)中大概存储16KB/(8B+8B)=1K个键值(因为是估值,为方便计算,这里的K取值为〖10〗^3)。

也就是说一个深度为3的B+Tree索引可以维护10^3 10^3 10^3 = 10亿 条记录。(这种计算方式存在误差,而且没有计算叶子节点,如果计算叶子节点其实是深度为4了)

我们只需要进行三次的IO操作就可以从10亿条数据中找到我们想要的数据,比起最开始的百万数据9000秒不知道好了多少个华莱士了。

而且在B+Tree上通常有两个头指针,一个指向根节点,另一个指向关键字最小的叶子节点,而且所有叶子节点(即数据节点)之间是一种链式环结构。所以我们除了可以对B+Tree进行主键的范围查找和分页查找,还可以从根节点开始,进行随机查找。

数据库中的B+Tree索引可以分为聚集索引(clustered index)和辅助索引(secondary index)。

上面的B+Tree示例图在数据库中的实现即为聚集索引,聚集索引的B+Tree中的叶子节点存放的是整张表的行记录数据,辅助索引与聚集索引的区别在于辅助索引的叶子节点并不包含行记录的全部数据,而是存储相应行数据的聚集索引键,即主键。

当通过辅助索引来查询数据时,InnoDB存储引擎会遍历辅助索引找到主键,然后再通过主键在聚集索引中找到完整的行记录数据。

不过,虽然索引可以加快查询速度,提高 MySQL 的处理性能,但是过多地使用索引也会造成以下弊端

创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加。

除了数据表占数据空间之外,每一个索引还要占一定的物理空间。如果要建立聚簇索引,那么需要的空间就会更大。

当对表中的数据进行增加、删除和修改的时候,索引也要动态地维护,这样就降低了数据的维护速度。

注意:索引可以在一些情况下加速查询,但是在某些情况下,会降低效率。

索引只是提高效率的一个因素,因此在建立索引的时候应该遵循以下原则:

在经常需要搜索的列上建立索引,可以加快搜索的速度。

在作为主键的列上创建索引,强制该列的唯一性,并组织表中数据的排列结构。

在经常使用表连接的列上创建索引,这些列主要是一些外键,可以加快表连接的速度。

在经常需要根据范围进行搜索的列上创建索引,因为索引已经排序,所以其指定的范围是连续的。

在经常需要排序的列上创建索引,因为索引已经排序,所以查询时可以利用索引的排序,加快排序查询。

在经常使用 WHERE 子句的列上创建索引,加快条件的判断速度。

现在大家知道索引为啥能这么快了吧,其实就是一句话,通过索引的结构最大化的减少数据库的IO次数,毕竟,一次IO的时间真的是太久了。。。

总结

就面试而言很多知识其实我们可以很容易就掌握了,但是要以学习为目的,你会发现很多东西我们得深入到计算机基础上才能发现其中奥秘,很多人问我怎么记住这么多东西,其实学习本身就是一个很无奈的东西,既然我们不能不学那为啥不好好学?去学会享受呢?最近我也在恶补基础,后面我会开始更新计算机基础和网络相关的知识的。

我是敖丙,你知道的越多,你不知道的越多,我们下期见!

人才们的 【三连】 就是敖丙创作的最大动力,如果本篇博客有任何错误和建议,欢迎人才们留言!

阅读 553 更新于 9月6日

 赞 10

 收藏 5

 分享

本作品系 原创, 采用《署名-非商业性使用-禁止演绎 4.0 国际》许可协议

敖丙

 算法工程师

 3.1k

关注作者

2 条评论

得票时间

提交评论

敖丙 (作者) : 

听说点赞的人都拿了大厂offer

 回复  今天 09:57

一毛 : 

第一张图描述和图对应是不是有点问题

 回复  31 分钟前

推荐阅读

七面阿里:现在分享一下阿里最全面试116题:阿里天猫、蚂蚁金服、阿里巴巴面试题含答案

工作第一年,往往是什么都充满新鲜感,什么都学习,冲劲十足的一年;WEB行业知识更新特别快,今天一个框架的新版本,明天又是另一个新框架,有时往往根据项目的需要来不断学习新东西;所有,很多时候感觉,自己用...

进击的java程序员  阅读 5.3k  78 赞

PHP面试MySQL数据库的面试题

你好,是我琉忆,PHP程序员面试笔试系列图书的作者。 本周(2019.3.4至3.8)的一三五更新的文章如下: 周一:PHP面试MySQL数据库的基础知识周三:PHP面试MySQL数据库的索引周五:PHP面试MySQL数据库的面试真题 今...

琉忆  阅读 3.3k  31 赞

PHPer面试指南-MySQL 篇

索引是一种特殊的文件,它们包含着对数据表里所有记录的引用指针,相当于书本的目录。其作用就是加快数据的检索效率。常见索引类型有主键、唯一索引、复合索引、全文索引。 索引创建的原则 最左前缀原理 选择区分...

今朝  阅读 1.7k  26 赞

为什么大家都说SELECT * 效率低

作者:陈哈哈来源:blog.csdn.net/qq_39390545/article/details/106766965面试官:“小陈,说一下你常用的SQL优化方式吧。” 陈小哈:“那很多啊,比如不要用SELECT *,查询效率低。巴拉巴拉...”面试官:“为什么不要...

民工哥  阅读 965  17 赞  5 评论

Mysql InnoDB B+树索引和哈希索引的区别? MongoDB 为什么使用B-树?

B+树是为磁盘及其他存储辅助设备而设计一种平衡查找树(不是二叉树)。B+树中,所有记录的节点按大小顺序存放在同一层的叶节点中,各叶节点用指针进行连接。

搜云库技术团队  阅读 2.7k  12 赞

最全阿里面试题合集118道+答案(阿里技术专家分享)

能进入阿里工作,是很多开发者们的目标与梦想,为帮助开发者们提升面试技能、高效通关一线互联网公司的面试,提炼总结了这份面试真题,一次整体放出送给大家。

JavaEdge  阅读 1k  4 赞

一份“热腾腾”的面经分享(涵盖国内知名大厂)

自我介绍Java中的多态为什么要同时重写hashcode和equalsHashmap的原理Hashmap如何变线程安全,每种方式的优缺点垃圾回收机制Jvm的参数你知道的说一下设计模式了解的说一下啊手撕一个单例模式算法题目

蛙哇  阅读 851  3 赞

一次 MySQL 索引面试,被面试官怼的体无完肤!

数据库索引,是数据库管理系统(DBMS)中一个排序的数据结构,它可以对数据库表中一列或多列的值进行排序,以协助更加快速的访问数据库表中特定的数据。通俗的说,我们可以把数据库索引比做是一本书前面的目录,它...

Java技术栈  阅读 587  3 赞

相关文章

  • 2020-09-07MySQL索引凭什么能让查询效率提高这么多?

    MySQL索引凭什么能让查询效率提高这么多? java后端mysql数据库面试 发布于 今天 09:00 背景 我...

  • 高级1、MySQL高级用法-索引20180515

    索引 主要目的:提高查询效率,对需要经常查询的字段添加索引,可有效提高查询效率。 简介 索引是一种特殊的文件(In...

  • 第十一节、索引

    什么是索引? 索引的出现就是为了提高数据查询的效率。 索引的常见模型 索引的出现时为了提高查询效率,但是实现索引的...

  • 索引如何提升查询效率

    MySQL的索引是如何提高查询效率的? 一.索引是什么? 索引是数据库中用来提高查询效率的技术,类似于目录。如果不...

  • 四、讲深入浅出索引(上)

    索引的出现其实就是为了提高数据查询的效率,就像书的目录一样。 4.1 索引的常见模型 索引的出现是为了提高查询效率...

  • MySQL索引凭什么让查询效率提高这么多?

    文章来源于公众号三太子敖丙 ,作者三太子敖丙 背景 我相信大家在数据库优化的时候都会说到索引,我也不例外,大家也基...

  • MySQL中的索引——概念篇

    使用索引的目的 使用索引的目的是提高数据库查询的效率。索引是怎么提高数据库查询的效率的呢?举个通俗的例子,查字典。...

  • 04 | 深入浅出索引(上)

    索引的出现其实就是为了提高数据查询的效率,就像书的目录一样。 索引的常见模型 索引的出现是为了提高查询效率,但是实...

  • 索引

    索引: why we use INDEX? 1,提高查询效率,查询方法 一、普通索引,index 创建方法: 1....

  • MYSQL数据库索引

    了解过MYSQL数据库的人,都知道索引能提高查询效率。那么为什么索引能提高查询效率?小编将自己的一些看法分享给大家...

网友评论

      本文标题:2020-09-07MySQL索引凭什么能让查询效率提高这么多?

      本文链接:https://www.haomeiwen.com/subject/ylflektx.html