mysql面试(五)
前言
本章节从数据页的具体结构,分析到如何生成索引,如何构成B+树的索引结构。
以及什么是聚簇索引,什么是联合索引
InnoDB数据结构
行数据
我看各种文档中有好多记录数据结构的,但是这些都是看完就忘的东西。在这里详细讲也没有多大用处,无非就是照本宣科而已。所以就不去一点点分析每个行数据中的详细内容,大概说一下每行的大概结构。
- 页是 MySQL 中磁盘和内存交互的基本单位,也是 MySQL 是管理存储空间的基本单位。
- 指定和修改行格式的语法如下:
CREATE TABLE 表名 (列的信息) ROW_FORMAT=行格式名称
ALTER TABLE 表名 ROW_FORMAT=行格式名称 - InnoDB 目前定义了4种行格式
COMPACT行格式:
Redundant行格式:
Dynamic和Compressed行格式:
这两种行格式类似于 COMPACT行格式 ,只不过在处理行溢出数据时有点儿分歧,它们不会在记录的真实
数据处存储字符串的前768个字节,而是把所有的字节都存储到其他页面中,只在记录的真实数据处存
储其他页面的地址。
数据页
前面说缓存页的时候,提过数据页的概念,那么这里详细说一下什么是数据页,以及数据页的结构是什么。
数据页,代表这块16kb大小的内存空间。里面存储了每个数据页的固定信息,和行记录数据。
大概就是这些内容,下面慢慢介绍里面每个内容。
如图:
数据记录
数据页中的数据记录,也就是我们上面说的行数据,这些行数据都是存放在User Records这个区域内。
当有数据需要存放的时候,先从Free Space中申请一个对应大小的空间,划分到User Records区域中,然后放入数据。当free space空间用完了,就证明这个数据页已经满了,需要新开一个数据页来继续存储数据。
如图:
这些数据单纯存储在这里肯定不行的,我们还需要管理一下,要不然查询的时候一个个数据页一条条数据去扒拉的话,还要数据页干啥。
首先,这些数据也是由链表方式存放在数据页中,每条数据都有一个指针来指向下一条数据。形成一个单向的链表结构。 并且,这个链表的头部和尾部是两个固定的虚拟节点,虚拟节点是存储在数据页中其他地方的。不在User Records中。
如图:
页目录(Page Directory)
现在已经把数据页中的所有数据记录串联起来了,但是想要查询的时候,好像还是要从头捋一遍,当然也是很耗时的。
那现在我们有了这个链表,也标记了最大数据和最小数据记录。
就可以把这个最大数据记录和最小数据记录单独存储起来,不就有了一个目录的功能么? 既然是目录了,肯定不会单纯的记录最大值和最小值咯。我们看书的时候,不也是分为一个个章节吗,这样能帮助我们更快的检索到数据所在位置。
所以为了制作这个目录, 需要将数据记录分为多个组,第一组肯定是最小数据,并且这个最小数据是单独划分出来一组,其他组的数据最多不能超过8个。然后把每个组中的最后一条记录数据地址进行单独存储。
如图:
查询的时候,就是通过二分法确定数据在哪个槽里面,然后获取到这个分组地址中最小记录数据地址。通过链表的指针捋一遍,查询到数据。
页面头部(Page Header)
有了上面的目录依旧是不够的,还需要得到一个数据页中存储的记录的状态信息,比如本页中已经存储了多少条记录,第一条记录的地址是什么,页目录中存储了多少个槽等等,特意在页中定义了一个叫 Page Header 的部分,它是数据页结构的第二部分,这个部分占用固定的 56 个字节,专门存储各种状态信息,大概内容如下:
文件头部(File Header)
数据页有了基本内容,有了介绍,有了目录。现在要做的就是把这些数据页串联起来,也形成链表的格式。File Header 作为第一个组成部分,它描述了一些针对各种页都通用的一些信息,比方说这个页的编号是多少,它的上一个页、下一个页是谁啦吧啦吧啦~ 这个部分占用固定的 38 个字节,是由下边这些内容组成的:
数据页和B+索引
前面我们大概说了一下数据页的结构,各个数据页可以组成一个 双向链表 ,而每个数据页中的记录会按照主键值从小到大的顺序组成一个 单向链表 ,每个数据页都会为存储在它里边儿的记录生成一个页目录 ,在通过主键查找某条记录的时候可以在 页目录 中使用二分法快速定位到对应的槽,然后再遍历该槽对应分组中的记录即可快速找到指定的记录。
页和记录的关系示意图如下:
因为这些 16KB 的页在物理存储上可能并不挨着,所以如果想从这么多页中根据主键值快速定位某些记录所在的页,我们需要给它们做个目录,每个页对应一个目录项,每个目录项包括下边两个部分:
页的用户记录中最小的主键值,我们用 key 来表示。
页号,我们用 page_no 表示。
所以我们为上边几个页做好的目录就像这样子:
以 页28 为例,它对应 目录项2 ,这个目录项中包含着该页的页号 28 以及该页中用户记录的最小主键值 5 。我们只需要把几个目录项在物理存储器上连续存储,比如把他们放到一个数组里,就可以实现根据主键值快速查找某条记录的功能了。比方说我们想找主键值为 20 的记录,具体查找过程分两步:
先从目录项中根据二分法快速确定出主键值为 20 的记录在 目录项3 中(因为 12 < 20 < 209 ),它对应的页是 页9 。
再根据前边说的在页中查找记录的方式去 页9 中定位具体的记录。
至此,针对数据页做的简易目录就搞定了。不过忘了说了,这个 目录 有一个别名,称为 索引 。
这些目录数据也是同样存在一个数据页中,这时候的数据页就称为目录页。
那当数据页的数据,上了几千几万几百万千万的时候,目录页肯定也不会是单单的几个而已。那么这些目录页也是要以同样的形式,通过前后指针形成数据页一样的链表。
那目录页多了,肯定也是要有查询方法的,所以目录页也会以同样的方式再统计一层目录。
这样一层一层的统计上去,如图。是不是看着有点熟悉? 没错,这就是B+树!
最下面的存放数据的数据页就是叶子节点,其他的目录页就称为非叶子节点或者内节点,最上面的节点也称为根节点
从图中可以看出来,一个 B+ 树的节点其实可以分成好多层,设计 InnoDB 的大叔们为了讨论方便,规定最下边的那层,也就是存放我们用户记录的那层为第 0 层,之后依次往上加。
之前的讨论我们做了一个非常极端的假设:存放用户记录的页最多存放3条记录,存放目录项记录的页最多存放4条记录。其实真实环境中一个页存放的记录数量是非常大的,假设,假设,假设所有存放用户记录的叶子节点代表的数据页可以存放100条用户记录,所有存放目录项记录的内节点代表的数据页可以存放1000条目录项记录,那么:
● 如果 B+ 树只有1层,也就是只有1个用于存放用户记录的节点,最多能存放 100 条记录。
● 如果 B+ 树有2层,最多能存放 1000×100=100000 条记录。
● 如果 B+ 树有3层,最多能存放 1000×1000×100=100000000 条记录。
● 如果 B+ 树有4层,最多能存放 1000×1000×1000×100=100000000000 条记录。哇咔咔~这么多的记录!!!
你的表里能存放 100000000000 条记录么?所以一般情况下,我们用到的 B+ 树都不会超过4层,那我们通过主键值去查找某条记录最多只需要做4个页面内的查找(查找3个目录项页和一个用户记录页),又因为在每个页面内有所谓的 Page Directory (页目录),所以在页面内也可以通过二分法实现快速定位记录,这不是很牛么,哈哈!
聚簇索引
上面说了B+树的构成,而这个B+树本身就是一个索引,有两个特点:
- 所有的记录也都是按照链表的方式排列的,排列方式是按照主键大小的顺序
- 叶子节点存储的就是完整的数据记录
而同时具有这两种特点的B+树就是聚簇索引,也就是说,每个表都会默认创建这个聚簇索引,不需要我们通过语句显式创建。需要注意的是,这个聚簇索引的叶子节点就是所有的数据记录,也就是说数据即索引,索引即数据。
二级索引
上面的聚簇索引只有在通过主键查询的时候才会发挥作用,但是在我们真正使用的时候,并不会全都按照主键来查询。那我们想要通过其他字段中的数据查询的时候该怎么处理?
这时候就可以用其他字段来建立一个新的B+树,不同的B+树使用不同的排序规则。比如我们上面是按照主键id建了一颗树,那这次按照另一个字段再建一颗,如图:
这个图中,黄色依旧是主键,蓝色是我们指定的索引字段。
● 首先是第一层的建立,这里就没有全量的数据了。为了和原本的记录关联,只用了索引字段和数据的主键id。把指定的索引字段按大小排列,如果相同的话再按主键排列。
● 第二层及以上就是通用的逻辑了,记录每页的最小索引值+页号。
当我们按照索引字段查询的时候,依旧是二分法查询。根据索引值的大小一层层的确定数据的页号所在。
最后找到索引+主键id的数据,但是这时候找到的并不是全量的数据记录。如果我们需要获取其他字段的数据,就需要拿着这些主键id,到聚簇索引中再次查询数据的全量字段,而这个动作就叫做回表查询。
为什么需要再次进行回表操作,直接吧数据存在这个索引中不好吗? 那样的话,就要把我们所有的数据存储两边了。而且,如果每新建一个索引,就把数据再复制一遍吗?那多大的内存也不够用啊。所以当通过这种其他字段建立的索引树进行查询的时候,还需要再次到聚簇索引进行一次回表操作才可以获取全量的数据记录。所以这种索引记录就称为二级索引,也可以称为辅助索引。
也就是说,只要是非主键建立的索引,全都是二级索引。
注意的一点,如果我们这个二级索引查询的时候,如果因为相同的数据太多,获取太多的记录页的话,就会导致获取到大量的主键id。然后拿着一批主键id再进行回表肯定会影响效率啊。
需要回表的数据越多,使用二级索引的性能就越低。本来我们建立一个二级索引,就是为了能提前筛选出更加精确的数据。如果二级索引查询一大堆数据的话,那这个索引还有使用的必要吗?
所以,在我们尽量要用数据更加散列的字段来建立索引
联合索引
既然可以使用其他字段建立索引了,那肯定也可以通过多个字段建立索引咯。可以如图:
这个与上面说的唯一不同区别就是,所有的记录页都增加了一个字段。优先按照第一个索引字段排序,相同的话再按照第二索引字段,依旧相同的话再按照第三索引字段。。。。最后是主键id排列。
主键依旧是只存在叶子节点中,每次查询,都要到最底层的叶子节点才可以获取主键id。
那这种通过多个字段建立的索引树就是联合索引。
既然我们建立索引的时候有排序的优先顺序,当然查询的时候,条件语句也是有优先顺序的。不过这个问题不用担心,mysql的查询优化器会优化我们传入的条件字段。按照最符合索引的方式进行排列。
明白了这个联合索引的排列顺序,那清楚为什么查询的时候要按照左侧优先了吗?
- 无论是索引条件还是字符串like查询的时候,都是按照左侧优先排序的。比如字符串“bai%”,在索引中肯定是先梳理到“b”开头的字符。如果直接“%du”,这种形式查询,就没有办法使用索引了。
- 多个字段查询也是这种顺序,比如我们现在的联合索引是idx_name_phone_address
那查询的时候,使用name+phone,就可以使用索引,但是直接用phone+address就无法用到这个二级索引了 - 还有排序,如果我们定义的排序规则同索引顺序相同的话,就可以直接使用索引排序。比如:order by name, phone; 但是如果反过来order by phone , name; 就无法直接使用索引进行排序了。
预告
下一章节单独列一下执行计划的各个参数定义
相关文章:

mysql面试(五)
前言 本章节从数据页的具体结构,分析到如何生成索引,如何构成B树的索引结构。 以及什么是聚簇索引,什么是联合索引 InnoDB数据结构 行数据 我看各种文档中有好多记录数据结构的,但是这些都是看完就忘的东西。在这里详细讲也没…...

微软全球蓝屏带来的思考及未来战争走向
微软全球蓝屏事件不仅揭示了技术层面的问题和挑战,还引发了对未来战争走向的一些深入思考。以下是关于这些思考的内容: 微软全球蓝屏带来的思考: 系统稳定性与安全性:微软全球蓝屏事件凸显了操作系统稳定性和安全性的重要性。一…...

以FastGPT为例提升Rag知识库应用中的检索召回命中率
提升Rag知识库应用中的检索召回命中率 在构建Rag(Retrieval-Augmented Generation)知识库应用时,检索召回知识片段的命中率是至关重要的。高效、准确的检索机制是确保AI系统能够精准响应用户查询的基础。当前,FastGPT主要采用三种…...

ffmpeg更改视频的帧率
note 视频帧率调整 帧率(fps-frame per second) 例如:原来帧率为30,调整后为1 现象:原来是每秒有30张图像,调整后每秒1张图像,看着图像很慢 实现:在每秒的时间区间里,取一张图像…...

设计模式13-单件模式
设计模式13-单件模式 写在前面对象性能模式典型模式1. 单例模式(Singleton Pattern)2. 享元模式(Flyweight Pattern)3. 原型模式(Prototype Pattern)4. 对象池模式(Object Pool Pattern…...

怎么给PDF文件加密码?关于PDF文件加密的四种方法推荐
怎么给PDF文件加密码?给PDF文件加上密码是保护文件安全的一种重要方法,特别是当需要在不受授权的访问下保护敏感信息时。这个过程不仅仅是简单地设置密码,而是涉及到对文档内容和访问控制的深思熟虑。加密PDF文件可以有效防止未经授权的用户查…...

GoFly快速开发框架基于Go语言和Vue3开发后台管理附件管理插件包
说明 为了给客户提供更好的交互体验,框架把附件管理独立打包成插件包,这样附件管理接可以做个不通需求的附件管理插件包来满足不同甲方客户需求。 目前附件插件包有2个:一个基础包、一个高级包 附件插件包功能 1.基础包 统一管理业务系统…...

matlab实验:实验六MATLAB 数值计算与符号运算
题目1:(线性方程组数值求解) 1. 用不同的方法求解下面方程:(方程原式参考 P369 实验 10,第 1 题) 第 1 种,左除和求逆函数(inv) 第 2 种 , 用 符 号 运 算 的…...

基于STM32设计的老人摔倒检测系统(4G+华为云IOT)(193)
文章目录 一、前言1.1 项目介绍【1】项目功能介绍【2】项目硬件模块组成1.2 设计思路【1】整体设计思路【2】整体构架【3】上位机开发思路【4】供电方式1.3 项目开发背景【1】选题的意义【2】可行性分析【3】参考文献【4】课题研究的意义【5】国内外技术发展现状【6】课题研究思…...

PyTorch和TensorFlow概念及对比
PyTorch和TensorFlow是两个流行的深度学习框架,用于构建和训练机器学习和深度学习模型。它们各自有一些独特的特点和优点: 一 、PyTorch 动态计算图: PyTorch使用动态计算图(Dynamic Computation Graph),…...

github的Codespaces是什么
目录 github的Codespaces是什么 一、定义与功能 二、特点与优势 三、工作原理 四、使用场景与限制 github的Codespaces是什么 GitHub的Codespaces是一个基于云的即时开发环境,它利用容器技术为开发者提供一个完全配置好的开发环境,以便他们能够直接在浏览器或通过Visua…...

Unity UGUI 之 图集
本文仅作学习笔记与交流,不作任何商业用途 本文包括但不限于unity官方手册,唐老狮,麦扣教程知识,引用会标记,如有不足还请斧正 本文在发布时间选用unity 2022.3.8稳定版本,请注意分别 1.什么是图集 精灵图…...

rust日常提问
rust 如何为类 添加一个函数 举例说明 在 Rust 中,我们通常使用 struct(结构体)来创建类似其他语言中的类(class)。Rust 中的结构体可以拥有关联函数(associated functions),这些函数…...

Vue3与Element-plus配合 直接修改表格中的一项数据——控制输入框的显示与隐藏
利用控制与隐藏输入框,直接修改表格中的每一项数据。 <!-- 表格模块 --> <div><el-table :data"tablelist" style"width: 100%"><el-table-column align"center" prop"deposit" label"接单押金">&l…...

设计模式--创建型
实现 #include <iostream> #include <memory>// 抽象产品类 class Product {public:virtual ~Product() {}virtual void Operation() const 0; };// 具体产品 类A class ConcreteProductA : public Product {public:virtual void Operation() const override {st…...

Vue3时间选择器datetimerange在数据库存开始时间和结束时间
♥️作者:小宋1021 🤵♂️个人主页:小宋1021主页 ♥️坚持分析平时学习到的项目以及学习到的软件开发知识,和大家一起努力呀!!! 🎈🎈加油! 加油!…...

鼠标移入事件 mouseover
<template><div><div mouseover"handleMouseOver">区域1</div></div> </template><script> export default {methods: {handleMouseOver() {console.log(鼠标悬停在区域1);}} } </script>...

UE4 自动换行——按排序关键字1.2.3.
要自动换行的字符串举例:“有效节点为:1.demo-worker-02 2.demo-worker-01 3.demo-master-01” 1.获取相邻两位字符串,组合后与关键字比较 2.当两位字符串与关键字相等,附加一次换行 3.其他例如 1)2)3)、(1)(2)(3)、<1><2><…...

Object.entries()解析出来的数组顺序乱了,健是string类型
现象: 从后端哪里拿到了一长串数据 const obj {"2023-07-01":10,"2023-09-18":2,"2023-10-10":3,"2024-01-10":1,"2024-01-12":1,"2024-02-20":4,"2024-07-01":4,... }; 比如上面的数据有一年的 并…...

SSM(Spring + Spring MVC + MyBatis)框架面试三道题
以下是三道关于SSM(Spring Spring MVC MyBatis)框架的面试题,由简单到困难进行排列: 1. 简答题:请简述Spring框架的核心特性。 答案: Spring框架的核心特性主要包括以下几个方面: 控制反转…...

ctfshow-web入门-php特性(web132-web136)
目录 1、web132 2、web133 3、web134 4、web135 5、web136 1、web132 存在 robots.txt 访问 /admin 需要传三个参数,并且需要满足: if($code mt_rand(1,0x36D) && $password $flag || $username "admin"){if($code admin){ech…...

通信原理-实验六:实验测验
实验六 实验测验 一:测验内容和要求 测试需要完成以下几个步骤: 配置好以下网络图;占总分10%(缺少一个扣一分)根据下面图配置好对应的IP和网关以及路由等相关配置,保证设备之间连通正常;占总…...

意得辑润色新用户注册直减15%
ABSJU202 优惠了很多...

重拾CSS,前端样式精读-函数(颜色,计算,图像和图形)
前言 本文收录于CSS系列文章中,欢迎阅读指正 在计算机编程中,函数有着重要的作用和意义,它可以实现封装,复用,模块化,参数等功能效果,在如何在CSS中写变量?一文带你了解前端样式利…...

经纬恒润与奇瑞汽车签订新能源项目重点供应商合作协议,共同开启合作新篇章
近日,2024年国家级芜湖经开区汽车零部件生态大会成功举行,经纬恒润受邀出席,与行业各伙伴齐聚经开区,同绘发展蓝图,助力经开区汽车产业高质量发展。会上,经纬恒润与奇瑞汽车签署合作协议,成为奇…...

@RestController和@Controller
RestController和Controller 在 Spring MVC 中,RestController 和 Controller 是用于定义控制器的注解,但它们有一些重要的区别。下面是对它们的详细解释和示例: Controller Controller 注解用于标记一个类是一个 Spring MVC 控制器&#…...

STM32-寄存器DMA配置指南
配置步骤 在STM32F0xx中文参考手册中的DMA部分在开头给出了配置步骤 每个通道都可以在外设寄存器固定地址和存储器地址之间执行 DMA 传输。DMA 传输的数据 量是可编程的,最大达到 65535。每次传输之后相应的计数寄存器都做一次递减操作,直到 计数为&am…...

【Django】anaconda环境变量配置及配置python虚拟环境
文章目录 配置环境变量配置python虚拟环境查看conda源并配置国内源在虚拟环境中安装django 配置环境变量 control sysdm.cpl,,3笔者anaconda安装目录为C:\ProgramData\anaconda3 那么需要加入path中的有如下三个 C:\ProgramData\anaconda3 C:\ProgramData\anaconda3\Scripts C:…...

保障企业数据主权:安全可控的爬虫工具与管理平台
摘要 在数据驱动的时代,企业对数据的需求日益增长,但如何在保障数据主权的前提下高效采集数据?本文深入探讨了选择安全可控爬虫工具与管理平台的重要性,分析了关键特性,并提出实用建议,助力企业维护数据安…...

NC重建二叉树
系列文章目录 文章目录 系列文章目录前言 前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。 描述 给定节点数为…...