[MySQL#10] 索引底层(1) | Page | 页目录

news2024/11/25 16:18:29

 目录

1. 初识索引

2. 认识磁盘

3. MySQL与磁盘交互基本单位

4. 索引的理解

1. 重谈Page

2. 为什么IO交互要用Page

3. 有主键的表插入数据时的排序

4. 单个Page与多个Page

4.1 单个Page

4.2 多个Page

目录

单Page目录

多Page目录


在看本文之前,可以回顾一下这两篇前文~

[MySQL#5] 表约束(2) | 唯一键 | 外键 | 简易商店数据库

【Linux】(26) 详解磁盘与文件系统:从物理结构到inode机制

1. 初识索引

  • 索引是提高数据库性能的关键工具。
  • 它通过改变数据的组织方式,显著提升查询速度,而无需增加硬件资源或修改应用程序代码。
  • 然而,索引的使用也并非没有代价。
  • 查询速度的提升是以插入、更新和删除操作的性能下降为代价的,因为这些写操作会增加大量的I/O操作。
  • 因此,索引的价值在于提高海量数据的检索速度。

MySQL的CURD操作与内存

  • 所有MySQL的CURD操作都在内存中进行。MySQL在启动时会预先开辟一大块内存空间,用于缓存数据。
  • 这些数据会在适当的时候被刷新到磁盘中进行持久化
  • 因此,MySQL服务器本质上是在内存中运行的,所有的数据库操作都在内存中进行。索引同样也是在内存中的一种特定结构
  • 索引是提高效率的,一般我们知道提高算法效率的因素:1. 组织数据的方式 ,2. 算法本身
  • 索引是更改特定组织数据的方式,把以前数据的组织方式以新的数据结构组织起来。所以索引是内存中一种特定组织的一种数据结构,具体是什么结构后面再说,

索引的类型

常见的索引类型包括:

  • 主键索引(Primary Key)
  • 唯一索引(Unique)
  • 普通索引(Index)
  • 全文索引(Fulltext)——主要用于解决中文索引问题

创建海量数据表

为了演示索引的效果,我们先创建一个包含800万条记录的表,并观察没有索引时的查询性能。

-- 产生随机字符串
delimiter $$
create function rand_string(n INT)
returns varchar(255)
begin
    declare chars_str varchar(100) default 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    declare return_str varchar(255) default '';
    declare i int default 0;
    while i < n do
        set return_str = concat(return_str, substring(chars_str, floor(1 + rand() * 52), 1));
        set i = i + 1;
    end while;
    return return_str;
end $$
delimiter ;

-- 产生随机数字
delimiter $$
create function rand_num()
returns int(5)
begin
    declare i int default 0;
    set i = floor(10 + rand() * 500);
    return i;
end $$
delimiter ;

-- 创建存储过程,向雇员表添加海量数据
delimiter $$
create procedure insert_emp(in start int(10), in max_num int(10))
begin
    declare i int default 0;
    set autocommit = 0;
    repeat
        set i = i + 1;
        insert into EMP (empno, ename, job, mgr, hiredate, sal, comm, deptno)
        values (start + i, rand_string(6), 'SALESMAN', 0001, curdate(), 2000, 400, rand_num());
    until i = max_num
    end repeat;
    commit;
end $$
delimiter ;

-- 执行存储过程,添加8000000条记录
call insert_emp(100001, 8000000);

注意:创建表单前要注意,恢复默认结束符:使用 delimiter ; 将结束符恢复为默认的分号 ;

查询性能测试

查询员工编号为998877的员工:

select * from EMP where empno = 998877;

没有索引时,查询非常慢,耗时约4.29秒。在实际项目中,如果放在公网中,同时有1000人并发查询,可能会导致系统崩溃。

解决方法:创建索引

alter table EMP add index(empno);

创建索引后,查询速度大幅提升。


2. 认识磁盘

硬件理解

MySQL 给用户提供存储服务,而存储的都是数据,数据在磁盘这个外设当中。

磁盘是计算机中的一个机械设备,相比于计算机其他电子元件,磁盘效率是比较低的,在加上IO本身的特征,可以知道,如何提升效率,是 MySQL 的一个重要话题。

磁盘结构

  • 扇区:数据库文件保存在磁盘的扇区中。每个扇区通常是512字节。
  • 柱面(Cylinder):同半径的磁道构成一个柱面。
  • 磁头(Heads):每个盘面有一个磁头,磁头和盘面的对应关系是1对1的。
  • CHS(Cylinder, Head, Sector):通过磁头、柱面和扇区编号定位扇区。
  • LBA(Logical Block Addressing):系统使用线性地址,最终转换为CHS。

再细看磁盘中一个盘片

扇区

数据库文件,本质其实就是保存在磁盘的盘片当中。也就是上面的一个个小格中,就是我们经常所说的扇区。当然,数据库文件很大,也很多,一定需要占据多个扇区。

题外话:

  • 从上图可以看出来,在半径方向上,距离圆心越近,扇区越小,距离圆心越远,扇区越大
  • 那么,所有扇区都是默认512字节吗?目前是的,我们也这样认为。因为保证一个扇区多大,是由比特位密度决定的。
  • 不过最新的磁盘技术,已经慢慢的让扇区大小不同了,不过我们现在暂时不考虑。
  • 我们在使用Linux,所看到的大部分目录或者文件,其实就是保存在硬盘当中的。(当然,有一些内存文件系统,如: proc , sys 之类,我们不考虑)
  • 建立数据库其实就是在linux下建立一个目录,建立一张表其就是在linux建立一个文件。

所以,最基本的,找到一个文件的全部,本质,就是在磁盘找到所有保存文件的扇区。

而我们能够定位任何一个扇区,那么便能找到所有扇区,因为查找方式是一样的。

定位扇区

  • 柱面(磁道): 多盘磁盘,每盘都是双面,大小完全相等。那么同半径的磁道,整体上便构成了一个柱面
  • 每个盘面都有一个磁头,那么磁头和盘面的对应关系便是1对1的
  • 所以,我们只需要知道,磁头(Heads)、柱面(Cylinder)(等价于磁道)、扇区(Sector)对应的编号。即可在磁盘上定位所要访问的扇区。这种磁盘数据定位方式叫做 CHS 。
  • 不过实际系统软件使用的并不是 CHS (但是硬件是),而是 LBA ,一种线性地址,可以想象成虚拟地址与物理地址。系统将 LBA 地址最后会转化成为 CHS ,交给磁盘去进行数据读取。不过,我们现在不关心转化细节,知道这个东西,让我们逻辑自洽起来即可。

结论

我们现在已经能够在硬件层面定位,任何一个基本数据块了(扇区)。那么在系统软件上,就直接按照扇区进行IO交互吗?不是

  • 如果操作系统直接使用硬件提供的数据大小进行交互,那么系统的IO代码,就和硬件强相关,换言之,如果硬件发生变化,系统必须跟着变化
  • 从目前来看,单次IO 512字节,还是太小了。IO单位小,意味着读取同样的数据内容,需要进行多次磁盘访问,会带来效率的降低。
  • 之前学习文件系统,就是在磁盘的基本结构下建立的,文件系统读取基本单位,就不是扇区,而是数据块。

故,系统读取磁盘,是以块为单位的,基本单位是 4KB 。

磁盘访问方式

  • 随机访问(Random Access):扇区地址不连续,磁头需要移动。
  • 连续访问(Sequential Access):扇区地址连续,磁头移动较少,效率较高。

3. MySQL与磁盘交互基本单位

软件理解

MySQL是一个应用层软件,依赖操作系统进行I/O操作。操作系统和磁盘之间的I/O单位是4KB,而MySQL为了提高效率,以16KB为单位先和 OS 进行I/O操作。

Buffer Pool

MySQL在内存中申请了一个大内存空间(Buffer Pool),用于缓存数据。默认大小为128MB。Buffer Pool用于减少磁盘I/O次数,提高查询性能。

I/O流程

  1. MySQL向操作系统请求16KB数据。
  2. 操作系统从磁盘读取4个4KB的数据块,加载到文件缓存区。
  3. 数据从文件缓存区加载到MySQL的Buffer Pool。
  4. MySQL在Buffer Pool中对数据进行处理。
  5. 更新数据时,MySQL将数据写入Buffer Pool,然后通过操作系统刷新到磁盘。

验证

  • 16*1024=16384
  • 磁盘这个硬件设备的基本单位是 512 字节,而 MySQL InnoDB引擎 使用 16KB 进行IO交互。
  • 即, MySQL 和磁盘进行数据交互的基本单位是 16KB 。
  • 这个 16KB 的基本数据单元,在 MySQL 这里叫做 page(注意和系统的page区分),它们是1:4的关系

共识要点

  1. MySQL以16KB page为单位进行I/O
  2. MySQL有Buffer Pool,数据先加载到Buffer Pool,再进行处理。
  3. 减少系统和磁盘I/O次数,一次I/O的数据量越大,效率越高。

以上就是我们学习索引的预备工作,下面正式开始学习索引~

4. 索引的理解

建立测试表

create table if not exists user (
    id int primary key,
    age int not null,
    name varchar(16) not null
) engine=InnoDB;

插入多条记录

insert into user (id, age, name) values (3, 25, 'Alice');
insert into user (id, age, name) values (1, 20, 'Bob');
insert into user (id, age, name) values (2, 22, 'Charlie');

查看插入结果

发现数据是有序的,这是因为MySQL会默认按照主键进行排序。

我们向一个具有主键的表中,乱序插入数据,发现数据会自动排序。谁做的?为什么这么做?

为了解决这个问题,我们需要重新探讨一下MySQL中的Page概念。

1. 重谈Page

数据读取流程

  • 磁盘上的文件数据:首先会被读到操作系统的文件缓存区中。
  • MySQL的Buffer PoolMySQL在启动时会为自己申请一个Buffer Pool,用于缓存数据。MySQL与操作系统之间进行I/O交互的基本单位是16KB,这是为了提高效率,减少I/O成本。

Page的概念

  • Page:MySQL的基本数据单位,大小为16KB。
  • Buffer Pool:可以加载多个Page,使用双向链表连接。

管理Page的方法

  • 先描述,再组织不要简单地将Page认为是一个内存块,Page内部也必须写入对应的管理信息。
  • 链表管理:所谓在MySQL中申请一个Page,实际上是new一个Page对象。然后将所有Page用“链表”的形式管理起来。我们在Buffer Pool内部对MySQL中的Page进行了建模。

2. 为什么IO交互要用Page

Page的重要性

  • 问题: MySQL和磁盘进行I/O交互时,采用Page方案的原因是为了提高效率。如果每次只加载需要的数据,例如查找id=2的记录,第一次加载id=1,第二次加载id=2,一次一条记录,那么就需要2次I/O。如果要找id=5,那么就需要5次I/O。
  • 批量加载:但如果这5条记录(或更多)都被保存在一个Page中(16KB,能保存很多记录),那么第一次I/O查找id=2时,整个Page会被加载到MySQL的Buffer Pool中完成一次I/O。此后如果查找id=1,3,4,5等,完全不需要进行I/O,而是在内存中进行。因此,在单Page内大大减少了I/O的次数。

局部性原理

  • 不能严格保证:我们不能严格保证用户下次查找的数据一定在同一个Page内,但有很大概率,因为有局部性原理。
  • 主要矛盾:IO效率低下的主要矛盾不是单次I/O数据量的大小,而是I/O的次数
3. 有主键的表插入数据时的排序

现象

  • 乱序插入,有序查询:我们向一个具有主键的表中,乱序插入数据,发现数据会自动排序。
  • 结论:数据最终以Page为单位进行管理,而Page是先描述后组织的

4. 单个Page与多个Page

4.1 单个Page

Page的定义

  • Page:一个Page可以看作是一个大的结构体,里面可以放很多数据,也有它自己的属性。
  • 数据承载:一个Page可以承载一部分数据,而一个文件可能很小也可能很大,因此MySQL建立的表可能会是一个或多个Page构成。

Page的特性

  • 大小:在MySQL中,每个Page的大小都是16KB。
  • 双向链表:Page使用prevnext指针构成双向链表,方便管理和遍历。

主键与排序

  • 主键:MySQL会默认按照主键对数据进行排序。
  • 无主键:如果没有主键,默认插入的顺序就是查询时的顺序。

为什么数据库在插入数据时要对其进行排序呢?我们按正常顺序插入数据不是也挺好的吗?

  • 目的:插入数据时排序的目的是优化查询的效率。Page内部的数据记录实质上是一个链表结构,链表的特点是增删快,查询修改慢。因此,有序的结构在查找时更加高效。
  • 优势:有序的数据在查找时从头到尾都是有效查找,没有任何一个查找是浪费的,而且如果运气好,可以提前结束查找过程。

4.2 多个Page

单Page的功能:在查询某条数据时,直接将一整页的数据加载到内存中,以减少硬盘IO次数,从而提高性能。

多Page的管理

  • 数据量大:如果有1千万条数据,需要多个Page来保存,多个Page彼此使用双链表链接起来,每个Page内部的数据也是基于链表的。
  • 线性查找:查找特定一条记录时,需要进行线性查找,效率较低,要遍历一万多条。

页目录的引入

  • 目录的作用:类似于书籍的目录,多花了空间但提高了效率。
  • 所以,目录,是一种“空间换时间的做法”

目录

单Page目录

牺牲page一部分保存数据的空间,把腾出来的空间用来保存目录,这所谓的目录里面只有两个字段

  • 第一个是它所指向起始位置的key值
  • 第二它有一个指针字段指向这条记录的起始位置

所以未来在查找key的时候,不需要在数据记录里面查找了,而是去目录中找

  • 先找到目录中对应key值的所处的起始位置
  • 然后在根据指针找到这条记录
  • 然后根据这条记录在向下遍历。
  • 虽然最后我们依旧需要遍历,但是是一个很小的子序列遍历了。效率也就大大提高了。

那么当前,在一个Page内部,我们引入了目录。比如,我们要查找id=4记录,之前必须线性遍历4次,才能拿到结果。现在直接通过目录2[3],直接进行定位新的起始位置,提高了效率。

现在我们可以再次正式回答上面的问题了,为何通过键值 MySQL 会自动排序?
可以很方便引入目录。

多Page目录

多Page的必要性

  • Page大小固定:MySQL中每一页的大小只有16KB,单个Page大小固定。
  • 数据量增长:随着数据量的不断增大,16KB不可能存下所有的数据,因此需要多个Page来存储数据。

Page的动态管理

  • 自动扩展:在单表数据不断被插入的情况下,MySQL会在容量不足时,自动开辟新的Page来保存新的数据。
  • 组织方式:通过指针的方式,将所有的Page组织起来,形成一个链表结构。

我们每次检索数据的时候,该从哪里开始呢?虽然顶层的目录页少了,但是还要遍历啊?

不用担心,可以再加目录页

多级目录:如果保存数据的Page变得非常多,上层的页目录也会变得非常多

  • 可以通过给上层页目录再加一层目录,形成多级目录结构

这就是传说中的B+树呀!没错,至此,我们已经给我们的表user构建完了主键索引。

随便找一个id=?

我们发现,现在查找的Page数一定减少了,也就意味着IO次数减少了,那么效率也就 提高了。


本篇文章小结:

  • Page:MySQL的基本数据单位,大小为16KB,用于提高I/O效率。
  • 主键与排序:MySQL会默认按照主键对数据进行排序,优化查询效率。
  • 多Page管理:通过页目录和B+树结构,提高多Page间的查找效率。

下篇文章继续讲解

  • B+树:节点不存储数据,叶子节点相连,适合范围查找。
  • 聚簇索引与非聚簇索引:InnoDB使用聚簇索引,MyISAM使用非聚簇索引,各有优劣。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

.net c# 使用 MailKit库接收139邮箱邮件

开发工具 vs2022&#xff0c;新建-控制台应用。项目完整代码下载&#xff1a; 要安装MailKit库 using MailKit; using MailKit.Net.Imap; using MimeKit; using System.Text; namespace MailKit_mail {internal class Program{static void Main(string[] args){//需要使用 Ma…

Centos开机自启动脚本示例

本文建议创建一个sh文件管理自启动的各项内容&#xff0c;再将sh文件设置开机启动 在/root/autoshell下创建一个autostart.sh&#xff0c;内容如下 #!/bin/bash # description:开机自启脚本# 启动mongodb sh /root/software/mongodb-linux-x86_64-rhel70-4.0.6/bin/mongod --c…

虚拟现实和增强现实技术,如何打造沉浸式体验?

内容概要 在这个科技飞速发展的时代&#xff0c;虚拟现实&#xff08;VR&#xff09;与增强现实&#xff08;AR&#xff09;技术的结合就像调皮的小精灵&#xff0c;一下子把我们的生活变得神奇又有趣。想象一下&#xff0c;你正在游戏中与精灵搏斗&#xff0c;突然间身边的客…

计算机网络 TCP/IP体系 数据链路层

一. 数据链路层的基本概念 数据链路层主要负责节点之间的通信&#xff0c;确保从物理层接收到的数据能够准确无误地传输到网络层。 数据链路层使用的信道主要有以下两种类型: 点对点信道: 这种信道使用一对一的点对点通信方式。广播信道: 这种信道使用一对多的广播通信方式,…

数据结构————链表

一、引言 1. 中间/头部的插入删除&#xff0c;时间复杂度为O(N) 2. 增容需要申请新空间&#xff0c;拷贝数据&#xff0c;释放旧空间。会有不小的消耗。 3. 增容一般是呈2倍的增长&#xff0c;势必会有一定的空间浪费。例如当前容量为100&#xff0c;满了以后增容到200&#x…

【网络原理】深入理解关于HTTP协议和报文的格式以及重要的属性

前言 &#x1f31f;&#x1f31f;本期讲解关于HTTP协议的重要的机制~~~ &#x1f308;感兴趣的小伙伴看一看小编主页&#xff1a;GGBondlctrl-CSDN博客 &#x1f525; 你的点赞就是小编不断更新的最大动力 &#x1f386;那么废话不…

【MyBatis源码】CacheKey缓存键的原理分析

文章目录 Mybatis缓存设计缓存KEY的设计CacheKey类主体CacheKey组成CacheKey如何保证缓存key的唯一性 Mybatis缓存设计 MyBatis 每秒过滤众多数据库查询操作&#xff0c;这对 MyBatis 缓存键的设计提出了很高的要求。MyBatis缓存键要满足以下几点。 无碰撞&#xff1a;必须保证…

面试题:JVM(二)

1. 面试题 简述 Java 类加载机制?&#xff08;百度&#xff09; JVM类加载机制 &#xff08;滴滴&#xff09; JVM中类加载机制&#xff0c;类加载过程&#xff0c;什么是双亲委派模型&#xff1f; &#xff08;腾讯&#xff09; JVM的类加载机制是什么&#xff1f; &#x…

数据库的使用02:SQLServer的连接字符串、备份、还原、SQL监视相关设置

目录 一、连接字符串 【本地连接字符串】 【远程连接字符串】 二、备份 三、还原 &#xff08;1&#xff09;还原数据库-bak、btn文件 &#xff08;2&#xff09;附加数据库mdf文件 四、SQL监视器的使用 一、连接字符串 【本地连接字符串】 server DESKTOP-FTH2P3S; Da…

【2024工业图像异常检测文献】UCAD: 使用对比学习提示的无监督连续异常检测方法

Unsupervised Continual Anomaly Detection with Contrastively-learned Prompt 1、Background 无监督异常检测&#xff08;UAD&#xff09;专注于在没有先验知识或标记实例的情况下识别数据中的不寻常模式或异常值&#xff0c;仅依赖于“正常”数据的内在分布&#xff08;Cha…

【算法】Floyd多源最短路径算法

目录 一、概念 二、思路 三、代码 一、概念 在前面的学习中&#xff0c;我们已经接触了Dijkstra、Bellman-Ford等单源最短路径算法。但首先我们要知道何为单源最短路径&#xff0c;何为多源最短路径 单源最短路径&#xff1a;从图中选取一点&#xff0c;求这个点到图中其他…

[C++]——哈希(附源码)

目录 ​编辑 ​编辑 一、前言 二、正文 2.1 unorder系列关联式容器 2.1.1 unordered_map 2.1.1.1 unorderer_map的介绍 ①unordered_map的构造 ②unordered_map的容量 ③unordered_map的迭代器 ④unordered_map的元素访问 ⑤unordered_map的查询 ⑥unordered_map的修改操…

使用Ubuntu快速部署MinIO对象存储

想拥有自己的私有云存储&#xff0c;安全可靠又高效&#xff1f;MinIO是你的理想选择&#xff01;这篇文章将手把手教你如何在Ubuntu 22.04服务器上部署MinIO&#xff0c;并使用Nginx反向代理和Let’s Encrypt证书进行安全加固。 即使你是新手&#xff0c;也能轻松完成&#xf…

Maven 下载配置 详解 我的学习笔记

Maven 下载配置 详解 我的学习笔记 一、Maven 简介二、maven安装配置三、maven基本使用四、idea配置mavenidea配置maven环境maven坐标idea创建maven项目配置Maven-Helper插件 五、依赖管理 一、Maven 简介 Apache Maven 是一个项目管理和构建工具&#xff0c;它基于项目对象模型…

一文带你了解,全国职业院校技能大赛老年护理与保健赛项如何备赛

老年护理与保健&#xff0c;作为2023年全国职业院校技能大赛的新增赛项&#xff0c;紧密贴合党的二十大精神&#xff0c;致力于加速健康与养老产业的蓬勃发展&#xff0c;并深化医养康养结合的服务模式。此赛项不仅承载着立德树人的教育使命&#xff0c;更通过竞赛的引领作用&a…

STM32ZET6-USART使用

一、原理说明 STM32自带通讯接口 通讯目的 通信方式&#xff1a; 全双工&#xff1a;通信时可以双方同时通信。 半双工&#xff1a;通信时同一时间只能一个设备发送数据&#xff0c;其他设备接收。 单工&#xff1a;只能一个设备发送到另一个设备&#xff0c;例如USART只有…

电话语音机器人,是由哪些功能构成?

电话语音机器人是自动电话销售、筛选意向客户的&#xff0c;只要录入好行业话术&#xff0c;导入要拨打的手机号&#xff0c;机器人就可以上岗工作了。 电话语音机器人组成部分&#xff1a; 1、语音识别器&#xff0c;主要作用&#xff1a;识别客户讲话内容&#xff0c;从而做…

理解 WordPress | 第二篇:结构化分析

WordPress 专题致力于从 0 到 1 搞懂、用熟这种可视化建站工具。 第一阶段主要是理解。 第二阶段开始实践个人博客、企业官网、独立站的建设。 如果感兴趣&#xff0c;点个关注吧&#xff0c;防止迷路。 WordPress 的内容和功能结构可以按照层级来划分&#xff0c;这种层次化的…

vue3项目history模式部署404处理,使用 historyApiFallback 中间件支持单页面应用路由

vue3项目history模式部署404处理&#xff0c;使用 historyApiFallback 中间件支持单页面应用路由 在现代的 web 开发中&#xff0c;单页面应用&#xff08;SPA&#xff09;变得越来越流行。这类应用通常依赖于客户端路由来提供流畅的用户体验&#xff0c;但在服务器端&#xf…

计算机毕业设计Hadoop+PySpark深度学习游戏推荐系统 游戏可视化 游戏数据分析 游戏爬虫 Scrapy 机器学习 人工智能 大数据毕设

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…