MySQL索引+常见问题详解

网络上的讲述MySQL索引的文章太多了,我打算换个角度来说。我们尝试着从设计者的角度思考,索引为什么这么设计。

假如你是索引的设计者,你会如何设计索引。我们不妨以新华字典为例。如果我们要查询汉字是什么意思,我们有如下操作

  • 确定拼音(假设你知道拼音,只是想要知道它的意思),ai
  • 找到拼音索引页
  • 找到字母A起始位置
  • 定位到ai,以及对应的页码

在这里插入图片描述

字典的数据部分

字典正文部分的内容,我们可以看成是数据页。每一个数据页都拥有自己的编码,也就是唯一标识——id。每一页都有一个起始汉字结束汉字

在这里插入图片描述

字典的索引部分

要让用户快速定位需要查询的内容,如果内容本身无法被快速定位,可以采取从数据中,提取部分冗余信息,构建成索引。然后将索引和内容,通过键值对映射(K-V) 的方式进行对应。

字典则是从每个汉字中,提取拼音这个冗余信息,作为上一层索引;然后从拼音中提取第一个字母,作为拼音的索引;最后将每个字母汇总在同一个索引页层级下,得到完整的索引结构。

我们将字典索引绘制,可以得到下方图案

在这里插入图片描述

tip:

  • 值得一提的是,在构建索引时,存在着非常多相同拼音的汉字。但索引目录不可能全部存储下。因此在构建索引时,只会存储最具代表性的那一个汉字,以及它所存在的页数
  • ai为例,索引中所记录的页数是拥有ai这个拼音,第一个汉字出现的位置。所以严格意义上将,字典的拼音索引并不全面。只有下方图示的索引结构,才能覆盖所有汉字
    在这里插入图片描述

现在,我们回到MySQL的设计中。我们需要解决两个问题:

  • 如何存储
  • 索引如何建立

不论是索引还是数据,我们都需要存储在文件中,我们不妨设计一个叫test.ibd的文件,用于存储我们的数据和索引。其中,test叫表名,.ibd为数据库表文件后缀。

我们可以把test.ibd看作现实世界中的《新华字典》。字典用一页页的纸张存储数据,我们test.ibd也可以划分出一页一页的空间来存放我们的表数据。

字典的每一页都有固定的大小。同样的,数据库的每一页我们也可以固定大小,就比如16K

在这里插入图片描述

tip:

  • InnoDB在物理层面以页(Page)为基本单位进行数据的读写和管理。每个页大小默认是16KB,并且这个大小是可以配置的。
  • 当InnoDB存储引擎需要分配新的空间来存储数据或者索引时,它会以页为单位进行分配。即使实际写入的数据不足一页(默认16KB),InnoDB也会完整地申请一个页的空间。
  • 据此,我们可以发现我们的.ibd文件全部都是16的倍数
    请添加图片描述
    请添加图片描述

存储的问题解决了,现在我们将视角聚焦于每一页的内容上。

我们可以将页划分为两列,一类是专门用于存储索引的——索引页,另一类专门存储数据的——数据页

我们先看数据页

数据页

按照直觉,我们很快就设计出了数据页的内容。首先,我们需要空间用来存用户数据,每一行用书数据都需要一个id作为唯一标识。另外我们需要页头存储页码信息。通过页码来唯一标识。具体如下图所示
在这里插入图片描述
现在我们来思考一个问题。假设我们现在找到了一页数据,我们如何定位逻辑上相邻的下一页数据呢?

对于字典来说,每一页都是物理相邻的,找到一页后顺着翻过去,就得到了另外一页。

但对于计算机来说,每一页都可能存储在磁盘的任何位置。因为磁盘最终会被划分为若干个单元格,操作系统不可能每次申请空间都恰好连续。随着文件的创建和删除,总会出现磁盘空间碎片的现象。如果是申请连续的大空间,这件事情难度过大。

考虑到数据页可能会分配在不同的空间,因此我们设计的时候需要增加指针,允许数据页找到彼此逻辑相连的数据页。

在这里插入图片描述
我们修改一下页的设计,通过添加前后指针,为页提供找到相邻页的能力

在这里插入图片描述


现在的页结构相对比较可用了,我们再完善一下,增加页目录、页尾这部分信息

在这里插入图片描述

我们思考这样一个问题,按照原来的逻辑,寻找数据只能全页遍历,这样的时间复杂度是n,如果用户数据非常多,那么所耗费的时间会非常大。

我们不妨将用户数据信息分组

  • 第一组,最小记录(id)所在组,且改组只有一个数据
  • 最后一组,最大记录(id)所在组,会有若干数据
  • 其余组尽量平均分配每组数据,控制在一定量内

然后,我们在页目录中记录若干slot,每个slot槽指向对应组中,最大数据的偏移地址。通过页目录构造出的数据结构,我们可以对原先的全遍历优化,通过二分的方式降低时间复杂度。从 o ( n ) − > o ( l o g n ) o(n)->o(log^n) o(n)>o(logn)

另外,我们增加页尾,提供页数据完整性校验的功能。

索引页

在正式讲索引页前,我们用一个小案例引入

假设,我们需要从一下数据页中查找id = 11的数据。在数据量小的情况下,我们全表遍历没什么问题。从第一页开始,挨个遍历所有行。但数据量大了,这种方式肯定是需要被淘汰的。我们需要提高搜索效率,这就是索引出现的原因。
在这里插入图片描述

索引页的设计我们依然沿用数据页的设计,不同的地方是索引页存储的内容是索引,且只存索引,而数据页存的是数据。这么做有个好处,当页只存储索引,那么每一页能够容纳更多的索引信息,从而提高索引范围,从而提高了数据的容量

那么索引页,我们该怎么存储索引信息呢?索引存储个啥呢?

在最开始我们提到,索引就是增加冗余信息。通过构建冗余信息来提高查询效率,这也算是空间换时间的一种具体实现。

我们将数据页的每一页最小的数据信息抽离出来,存储到索引页中。形成索引页,具体如下图

在这里插入图片描述
现在我们要查询id = 11的数据,我们先遍历索引页,发现11在9 ~ 12之间,因此定位到页3,然后在页3中根据页目录的信息进行二分,找到11号数据。引入索引页,我们能够更快的定位到数据信息。

此外,随着数据的引入,索引页的增长数量是非常缓慢的。按照上图所示逻辑,一份索引页能够索引到4张不同的页。假设我们是3层数结构,且全部填满。一、二两层用于存储索引页、三层用于存储数据页,我们可以容纳的数据量是 1 ∗ 4 ∗ 4 ∗ 4 = 64 1 * 4 * 4 * 4 = 64 1444=64行数据
计算公式位 n = z ( h − 1 ) ∗ y 其中 , n 表示数据量 , z 表示索引页存储的数据 y 表示数据页存储数据量 h 表示树的高度 计算公式位n = z ^ {(h - 1)} * y \\ 其中, n表示数据量, z表示索引页存储的数据\\y表示数据页存储数据量\\ h表示树的高度 计算公式位n=z(h1)y其中,n表示数据量,z表示索引页存储的数据y表示数据页存储数据量h表示树的高度
假设我们现在拥有5层的树高,且全部填满,带入公式可得, n = 1024 n = 1024 n=1024

我们用python将数据可视化

在这里插入图片描述
不难发现,随着h(树高)轻微的变化,n(数据量)指数式增长。这便是构建树形索引页的好处。

至此,我们的索引设计基本完成!


MySQL单表最大数据容量2000万?

有了上文所说的内容,这个数据的判断起始不难。

假设我们拥有三层满树结构,且页的大小默认为16K,除去其余的信息,索引页能够存储的索引信息只有15K,假设每一行数据占用空间12B,由 15 ∗ 1024 / 15 = 1280 15 * 1024 / 15 = 1280 151024/15=1280 可得,索引页在假设条件下可以索引1280页数据信息。

数据页同理,拥有15K的存储数据的空间,每行数据1K,那么数据页能够存储的数据为15行

带入上一节的公式 n = z ( h − 1 ) ∗ y n = z ^ {(h - 1)} * y n=z(h1)y, 计算得到 n = 24576000 n = 24576000 n=24576000,也就是2000万。

当然,这个数据不绝对。如果行数据大小小于1K,那么容量还得翻一番。

另外,值得一提的是,树的高度决定了磁盘IO的次数

前文我们提到每一页都是存储在磁盘不同的位置。在通过索引查找数据时,遍历了多少页,就意味着进行了多少次IO操作。


MySQL为什么采用B+树?

B+树具有如下优点

  • B+树是多叉树,每一层能够索引的节点量非常庞大。在树的层级确定的情况下,能够容纳更多的数据
  • B+树索引部分只存储索引,不存储数据,因此能够存储更多的索引,从而容纳更多的数据(B树,会将一部分数据充当索引)
  • B+树的所有数据都存储在叶子节点,并且通过指针顺序相连。因此B+树支持范围查询

聚簇索引 / 非聚簇索引

聚簇索引

我们直接看官方是怎么说的

Each InnoDB table has a special index called the clustered index that stores row data. Typically, the clustered index is synonymous with the primary key.

聚簇索引,叶子节点存储的是完整一行的数据,它和主键相关。

我们用图来演示

假设我们创建了test表,其中存储如下数据

在这里插入图片描述

我们为主键创建聚簇索引,create unique index jucu_index on test(id)

得到如下的索引图

在这里插入图片描述
叶子节点存放了完整一行的数据

非局促索引

Indexes other than the clustered index are known as secondary indexes. In InnoDB, each record in a secondary index contains the primary key columns for the row, as well as the columns specified for the secondary index. InnoDB uses this primary key value to search for the row in the clustered index.

在innodb中,只要不是聚簇索引,就是非局促索引。非聚簇索引叶子节点包含了每一行的主键。innodb再用主键的值,在聚簇索引中查询整行信息

我们为age字段创建普通索引,create index nianning_index on test(age)

索引图如下

在这里插入图片描述
每个叶子节点存储的是主键,而不是每一行的信息

回表 / 索引覆盖

回表

回表是指当查询过程中根据非聚簇索引找到行的键值后,缺少需要列信息,所以需要根据主键再次回到聚簇索引的数据区去查找对应的完整行记录的过程

我们以上一节的例子为例

select * from test where age = 30; 这段SQL会走age的非聚簇索引。找到age = 30所对应的节点后,节点只存储了id信息,缺少了其他的信息。因此需要通过找到的id信息,返回聚簇索引中找到全部的信息。

在这里插入图片描述

覆盖索引

索引包含了查询所涉及的所有列,因此数据库可以直接从索引结构中检索所有需要的数据,无需进行额外的“回表”操作来读取磁盘上的实际数据行

依然以test数据库为例

select id, age from test where age = 30;这个SQL就是覆盖索引。因为在age上创建的索引就包含了需要查询的所有信息,无需进行回表

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/446373.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【读书笔记】针对ICS的ATTCK矩阵详解(一)

Techniques - ICS | MITRE ATT&CKhttps://attack.mitre.org/techniques/ics/ 一、初始访问(Initial Access) 该阶段:攻击者正在尝试进入ICS环境。 初始访问包括攻击者可能用作入口向量,从而可以在 ICS 环境中获得初始立足点的…

怎么在学习强国网上发布文章,学习强国投稿发稿方法途径,附学习强国多少钱价格明细表

学习强国是一款受用户欢迎的学习软件,许多人希望在其平台上发布自己的文章,以分享和传播自己的学习成果和心得体会。那么,怎么在学习强国网上发布文章呢?接下来,我们将介绍一些投稿发稿的方法和途径。 首先&#xff0c…

PLC的FC与FB模块程序的功能解析

前文讲了在西门子系列的PLC中四个程序模块的描述,从S7-1200PLC开始就有FC和FB程序块了,但在使用的时候,一些使用者还是不好理解,以至于不知道该如何选择。今天,我们就用大白话的方式给大家讲解FC与FB的功能。 1、FC与…

Python打印Linux系统中最常用的linux命令之示例

一、Linux中的~/.bash_history文件说明: 该文件保存了linux系统中运行过的命令的历史。使用该文件来获取命令的列表,并统计命令的执行次数。统计时,只统计命令的名称,以不同参数调用相同的命令也视为同一命令。 二、示例代码&am…

数据结构二叉树续

在前边我们讲完了二叉树的一些代码结构 现在呢我们需要进一步去细化 我们传参数组后,让数组里面的数据进行调整 如何调整成堆呢? 建堆 所以我们分装一个成堆的函数 还是先去断言 然后创建空间 这里我们需要用到一个memcpy函数 memcpy函数是用来…

RabbitMQ - 07 - 通过注解创建队列和交换机

之前消息模型的实现,都是通过rabbitMQ Management 控制台来手动创建 queue 和 exchange 的 在项目开发中有两种方式通过代码声明 创建 一种是通过 Bean 方式,这种代码量较大 稍繁琐 一种是通过注解的方式声明 先编写消费者代码 通过注解绑定了 消息队列,交换机,还有 routin…

预约自习室

预约自习室 1、技术介绍 自习室预约系统的后端开发语言采用Node,后端开发框架采用Express,数据库采用的Node的最佳搭档MySQL。采用Vue作为前端开发框架,Element-UI作为开发的组件库,微信小程序。期间采用axios实现网页数据获取&a…

Linux 进程程序替换

💓博主CSDN主页:麻辣韭菜-CSDN博客💓   ⏩专栏分类:http://t.csdnimg.cn/G90eI⏪   🚚代码仓库:Linux: Linux日常代码练习🚚   🌹关注我🫵带你学习更多Linux知识   🔝&#x1f5…

springboot257基于SpringBoot的中山社区医疗综合服务平台

中山社区医疗综合服务平台的设计与实现 摘 要 传统信息的管理大部分依赖于管理人员的手工登记与管理,然而,随着近些年信息技术的迅猛发展,让许多比较老套的信息管理模式进行了更新迭代,居民信息因为其管理内容繁杂,管…

车载诊断协议DoIP系列 —— 传输层控制协议(TCP)用户数据报协议(UDP)

车载诊断协议DoIP系列 —— 传输层控制协议(TCP)&用户数据报协议(UDP) 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师(Wechat:gongkenan2013)。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 本就是小人物,输了就是输了,不要在意别人怎…

【notepad++工具使用之】批量加逗号

背景 在使用sql语句in关键字查询时,我们需要把数据用逗号进行隔开,在数据量非常少的时候(十几二十个这样),可以手动的去加逗号分隔符; 但是遇到1000个怎么弄呢? 强大的Notepad 批量处理数据时…

macOS14.4安装FFmpeg及编译FFmpeg源码

下载二进制及源码包 二进制 使用brew安装ffmpeg : brew install ffmpeg 成功更新到ffmpeg6.1 下载FFmpeg源码

CSS拖曳盒子案例

让我为大家带来一个小案例吧&#xff01; <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title><style>* {margin: 0;padding: 0;}.box1 {width: 100px;height: 100px;background-color: black;margin-bot…

【MATLAB第99期】#源码分享 | 基于MATLAB的SHEPard模型多输入单输出回归预测模型

【MATLAB第99期】#源码分享 | 基于MATLAB的SHEPard模型多输入单输出回归预测模型 Shepard模型(简称SP模型)就是一种直观的、可操作的相似预测法&#xff0c;常用于插值。相似预测法基本原理按照相似原因产生相似结果的原则&#xff0c;从历史样本中集中找出与现在的最相似的一…

Vue class和style绑定:动态美化你的组件

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

代码随想录训练营第40天 | LeetCode 343. 整数拆分

LeetCode 343. 整数拆分 文章讲解&#xff1a;代码随想录(programmercarl.com) 视频讲解&#xff1a;动态规划&#xff0c;本题关键在于理解递推公式&#xff01;| LeetCode&#xff1a;343. 整数拆分_哔哩哔哩_bilibili 思路 代码如下&#xff1a; ​​​​​​LeetCode 96…

如何快速开发高性能步进电机控制驱动系统RS485 UART通讯Modebus协议防丢步节能静音驱动TMCM1290

TMCM-1290是一款4-36V供电的智能集成步进电机驱动器控制器模块&#xff0c;它融合了步进电机的运动控制和驱动功能&#xff0c;为现代工业应用提供了高效、可靠的解决方案。以下是关于TMCM-1290的详细介绍&#xff1a; 一、产品特点 集成度高&#xff1a;TMCM-1290将步进电机…

检测虚拟机环境的常见技术

下面列出检测 VMware 虚拟机的常见技术&#xff1a; #include <iostream> #include <windows.h> #include <sysinfoapi.h> #include <comdef.h> #include <Wbemidl.h> #include <ShlObj.h> #include <LM.h> #include <TlHelp32.…

DxO PureRAW:赋予RAW图像生命,打造非凡视觉体验 mac/win版

DxO PureRAW 是一款专为RAW图像处理而设计的软件&#xff0c;旨在帮助摄影师充分利用RAW格式的优势&#xff0c;实现更加纯净、细腻的图像效果。该软件凭借其强大的功能和易于使用的界面&#xff0c;成为了RAW图像处理领域的佼佼者。 DxO PureRAW 软件获取 首先&#xff0c;Dx…

Appcms存储型XSS漏洞复现

君衍. 一、环境介绍二、环境部署三、测试回显四、多次注入1、第一条评论2、第二条评论3、管理员登录查看 五、编写脚本获取cookie 一、环境介绍 这里需要注意&#xff0c;我没有找到原有的该环境源码包&#xff0c;因为这个是很久前的漏洞了&#xff0c;在XSS学习中可以查看下…