【MySQL 保姆级讲授】深层理解索引及其特性(重点)--上(11) ...

农民  金牌会员 | 2024-11-11 17:31:06 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 764|帖子 764|积分 2292

1. MySQL与内存和磁盘的联系

我们全部的MySQL数据操作(增删查改),全部是在MySQL的内存中举行的。MySQL在启动的时间会预先开辟一大块内存空间,在合适的时间把我们对数据的操作体如今内存级,MySQL定期的把数据刷新到外设(磁盘)做恒久化。
mysql的服务器本质是在内存中的,全部的数据库的CURD操作全部是在内存中举行的,索引也是如此
进步算法服从的因素:1.构造数据的方式,2.算法本身
索引是特定的数据布局构造的布局
2. 认识磁盘

2.1 MySQL与存储

MySQL与存储
MySQL 给用户提供存储服务,存储的都是数据,而数据在磁盘这个外设当中。磁盘是计算机中的一个机
械设备,相比于计算机其他电子元件,磁盘服从是比力低的,在加上IO本身的特征,可以知道,如何进步服从,是MySQL 的一个重要话题。
2.2 磁盘布局


磁盘中的一个盘片

2.3 扇区

数据库文件,本质实在就是保存在磁盘的盘片当中。也就是上面的一个个小格子中,就是我们经常所说的扇区。固然,数据库文件很大,也很多,一定需要占据多个扇区。
从上图可以看出来,在半径方向上,距离圆心越近,扇区越小,距离圆心越远,扇区越大
那么,全部扇区都是默认512字节吗?现在是的,我们也如许以为。由于包管一个扇区多大,是由比特位密度决定的。
不过最新的磁盘技术,已经慢慢的让扇区巨细不同了,不过我们如今临时不讨论。
我们在利用Linux,所看到的大部门目次或者文件,实在就是保存在硬盘当中的。(固然,有一些内存文
件系统,如:proc ,sys 之类,我们不讨论)
数据库文件,本质实在就是保存在磁盘的盘片当中,就是一个一个的扇区。
怎么检察数据库文件呢?
展示:
/var/lib/mysql目次:
用于存储 MySQL 数据库的数据文件,包罗表数据、索引、日志文件等。
这个目次是 MySQL 数据库的核心存储位置
检察MySQL数据库中的文件:
进入目次:cd /var/lib/mysql
检察文件:ls

创建一个数据库,再创建一个表,然后子再插入数据:
  1. create database test_database;
  2. use test_database;
  3. create table t1 (id int, name varchar(10));
  4. insert into t1 values(1,'李明'), (2,'李白');
复制代码

看创建的文件在linux中的位置
进入目次:cd /var/lib/mysql
检察文件:ls

显然,多了一个目次–我们刚才创建的数据库。
进入该数据库并检察文件
命令:cd test_database;
检察:ls

显然,我们可以看到创建的表。
db.opt这个文件包罗了数据库的一些选项和参数,例如字符集编码、排序规则等。它是 MySQL 创建数据库时自动生成的一个文本文件。
t1.frm这个文件是表定义文件,包罗了表的布局信息,如字段名称、类型、长度、是否允许为空等。frm 文件是 MySQL 表的元数据文件,用于描述表的布局。
t1.ibd这个文件是表数据文件,包罗了表的实际数据和索引。ibd 文件是 InnoDB 存储引擎特有的数据文件格式,用于存储表的数据和索引信息。
以是,最根本的,找到一个文件的全部,本质,就是在磁盘找到全部保存文件的扇区。而我们能够定位任何一个扇区,那么便能找到全部扇区,由于查找方式是一样的。
2.4 定位扇区




  • 柱面(磁道): 多盘磁盘,每盘都是双面,巨细完全相称。那么同半径的磁道,整体上便构成了一个柱面
  • 每个盘面都有一个磁头,那么磁头和盘面的对应关系便是1对1的
  • 只需要知道,磁头(Heads)、柱面(Cylinder)(等价于磁道)、扇区(Sector)对应的编号。即可在磁盘上定位所要访问的扇区。这种磁盘数据定位方式叫做CHS,不过实际利用的并不是CHS(但是硬件是),而是LBA ,一种线性地址,可以想象成虚拟地址与物理地址。系统将LBA地址末了会转化成为CHS ,交给磁盘去举行数据读取。不过,我们如今不关心转化细节,知道这个东西,让我们逻辑自洽起来即可。
结论
我们如今已经能够在硬件层面定位,任何一个根本数据块了(扇区)。那么在系统软件上,就直接按照扇区(512字节,部门4096字节),举行IO交互吗?
答:不是
如果操作系统直接利用硬件提供的数据巨细举行交互,那么系统的IO代码,就和硬件强相关,换言之,如果硬件发生变化,系统必须跟着变化。
从现在来看,单次IO 512字节,照旧太小了。IO单位小,意味着读取同样的数据内容,需要举行多
次磁盘访问,会带来服从的降低
之前学习文件系统,就是在磁盘的根本布局下建立的,文件系统读取根本单位,就不是扇区,而是
数据块。
故,系统读取磁盘,是以块为单位的,根本单位是4KB
磁盘随机访问(Random Access)与一连访问(Sequential Access)


  • 随机访问:本次IO所给出的扇区地址和上次IO给出扇区地址不一连,如许的话磁头在两次IO操作之间需要作比力大的移动动作才能重新开始读/写数据。
  • 一连访问:如果当次IO给出的扇区地址与上次IO结束的扇区地址是一连的,那磁头就能很快的开始这次IO操作,如许的多个IO操作称为一连访问。
  • 因此尽管相邻的两次IO操作在同一时刻发出,但如果它们的哀求的扇区地址相差很大的话也只能称为随机访问,而非一连访问。
  • 磁盘是通过机械运动举行寻址的,一连访问不需要过多的定位,故服从比力高
为什么是4kb呢?
内存被分为多个4kb巨细的块,为了让磁盘数据和内存数据举行更好的I/O交互
也考虑到 I/O 服从和解耦,磁盘需要被操作系统访问,4kb的巨细是一种弃取,采用局部性原理来进步整机的服从
3. MySQL与磁盘交互根本单位

而MySQL作为一款应用软件,可以想象成一种特殊的文件系统。它有着更高的IO场景,以是,为了进步
根本的IO服从,MySQL 举行IO的根本单位是16KB (背面同一利用InnoDB 存储引擎讲解)
查询MySQL举行IO的根本单位:
命令:show global status like 'innodb_page_size;'

16389的单位是字节,1638/1024 = 16 KB
也就是说,磁盘这个硬件设备的根本单位是512 字节,而MySQL innodb引擎利用16KB举行交互,即MySQL 和磁盘举行数据交互的根本单位是16KB 。这个根本数据单元,在MySQL 这里叫做page(注意和系统的page区分)
从逻辑上看,MySQL好像和磁盘之间是16KB举行交互,但是MySQL是不能直接与磁盘举行交互的,能与磁盘举行交互的只有操作系统。实际上在操作系统中有文件缓冲区,mysql对操作系统举行16kb的交互,操作系统对磁盘举行4*4kb的交互。

4. 建立共识



  • MySQL 中的数据文件,是以page为单位保存在磁盘当中的。
  • MySQL 的CURD 操作,都需要通过计算,找到对应的插入位置,或者找到对应要修改或者查询的数
    据。
  • 而只要涉及计算,就需要CPU参与,而为了便于CPU参与,一定要能够先将数据移动到内存当中。
  • 以是在特定时间内,数据一定是磁盘中有,内存中也有。后续操作完内存数据之后,以特定的刷新
    战略,刷新到磁盘。而这时,就涉及到磁盘和内存的数据交互,也就是IO了。而此时IO的根本单位
    就是Page。
  • 为了更好的举行上面的操作, MySQL 服务器在内存中运行的时间,在服务器内部,就申请了被称为Buffer Pool的的大内存空间,来举行各种缓存。实在就是很大的内存空间,来和磁盘数据举行IO交互。
  • 为了更高的服从,一定要尽可能的镌汰系统和磁盘IO的次数。

5. 索引的理解

5.1 建立一个表并查询

建立一个表(设置主键索引)
  1. create table user (
  2. id int primary key,     
  3. age int not null,
  4. name varchar(16) not null
  5. );
复制代码
我的默认利用 innodb存储引擎

插入数据,id的序次随机
  1. insert into user (id, age, name) values(3, 18, '杨过');
  2. insert into user (id, age, name) values(4, 16, '小龙女');
  3. insert into user (id, age, name) values(2, 26, '黄蓉');
  4. insert into user (id, age, name) values(5, 36, '郭靖');
  5. insert into user (id, age, name) values(1, 56, '欧阳锋');
复制代码
查询数据:
命令:select * from user;

没有利用排序命令,为什么查询效果是排序的呢?
下面慢慢表明。
5.2 为何 I/O 交互要是Page

为何MySQL和磁盘举行IO交互的时间,要采用Page的方案举行交互呢?用多少,加载多少不香吗?
如上面的5条纪录,如果MySQL要查找id=2的纪录,第一次加载id=1,第二次加载id=2,一次一条纪录,那么就需要2次IO。如果要找id=5,那么就需要5次IO
但,如果这5条(或者更多)都被保存在一个Page中(16KB,能保存很多纪录),那么第一次IO查找id=2的时
候,整个Page会被加载到MySQL的Buffer Pool中,这里完成了一次IO。但是今后如果在查找id=1,3,4,5等,完全不需要举行IO了,而是直接在内存中举行了。以是,就在单Page里面,大大镌汰了IO的次数。
怎么包管,用户一定下次找的数据,就在这个Page里面?我们不能严格包管,但是有很大概率,由于有局部性原理。通常IO服从低下的最主要矛盾不是IO单次数据量的巨细,而是IO的次数
理解的单个Page
MySQL 中要管理很多数据表文件,而要管理好这些文件,就需要先描述,再构造,我们现在可以简单的理解成一个个独立文件是有一个或者多个Page构成的,每个Page像链表一样链接起来。

不同的Page,在MySQL 中,都是16KB ,利用由于有主键的问题,prev 和next 构成双向链表MySQL 会默认按照主键给我们的数据举行排序,从上面的Page内数据纪录可以看出,数据是有序且彼此关联的。
为什么数据库在插入数据时要对其举行排序呢?我们按正常序次插入数据不是也挺好的吗?
插入数据时排序的目标,就是优化查询的服从。
页内部存放数据的模块,实质上也是一个链表的布局,链表的特点也就是增删快,查询修改慢,以是优化查询的服从是必须的。
正是由于有序,在查找的时间,从头到后都是有效查找,没有任何一个查找是浪费的,而且,如果运气好,是可以提前结束查找过程的
理解多个Page
通过上面的分析,我们知道,上面页模式中,只有一个功能,就是在查询某条数据的时间直接将一
整页的数据加载到内存中,以镌汰硬盘IO次数,从而进步性能
。但是,我们也可以看到,如今的页
模式内部,实际上是采用了链表的布局,前一条数据指向后一条数据,本质上照旧通过数据的逐条
比力来取出特定的数据

如果有1千万条数据,一定需要多个Page来保存1千万条数据,多个Page彼此利用双链表链接起
来,而且每个Page内部的数据也是基于链表的。那么,查找特定一条纪录,也一定是线性查找。这
服从也太低了


那么,怎么进步查询的服从呢?
页目次
我们在看《谭浩强C程序计划》这本书的时间,如果我们要看<指针章节>,找到该章节有两种做法:

  • 从头逐页的向后翻,直到找到目标内容
  • 通过书提供的目次,发现指针章节在234页(假设),那么我们便直接翻到234页。同时,查找目次的方案,可以序次找,不过由于目次肯定少,以是可以快速进步定位本质上,书中的目次,是多花了纸张的,但是却进步了服从以是,目次,是一种“空间换时间的做法”
单页环境
针对上面的单页Page,我们能否也引入目次呢?
固然可以

那么当前,在一个Page内部,我们引入了目次。好比,我们要查找id=4纪录,之前必须线性遍历4次, 才能拿到效果。如今直接通过目次2[3]`,直接举行定位新的起始位置,进步了服从。
如今我们可以再次正式回答上面的问题了,为何通过键值MySQL 会自动排序?
可以很方便引入目次
多页环境
MySQL 中每一页的巨细只有16KB ,单个Page巨细固定,以是随着数据量不停增大,16KB 不可能存下全部的数据,那么必定会有多个页来存储数据。

在单表数据不停被插入的环境下,MySQL 会在容量不足的时间,自动开辟新的Page来保存新的数据,然后通过指针的方式,将全部的Page构造起来。
需要注意,上面的图,是理想布局,各人也知道,现在要包管整体有序,那么新插入的数据,不一定会
在新Page上面,这里仅仅做演示。
如许,我们就可以通过多个Page遍历,Page内部通过目次来快速定位数据。可是,貌似如许也有服从问
题,在Page之间,也是需要MySQL 遍历的,遍历意味着依旧需要举行大量的IO,将下一个Page加载到内存,举行线性检测。如许就显得我们之前的Page内部的目次,有点杯水车薪了。
那么如何解决呢?解决方案,实在就是我们之前的思绪,给Page也带上目次。


  • 利用一个目次项来指向某一页,而这个目次项存放的就是将要指向的页中存放的最小数据的键值
  • 和页内目次不同的地方在于,这种目次管理的级别是页,而页内目次管理的级别是行
  • 此中,每个目次项的构成是:键值+指针。图中没有画全。

存在一个目次页来管理页目次,目次页中的数据存放的就是指向的那一页中最小的数据。有数据,就可
通过比力,找到该访问那个Page,进而通过指针,找到下一个Page。
实在目次页的本质也是页,平凡页中存的数据是用户数据,而目次页中存的数据是平凡页的地址
可是,我们每次检索数据的时间,该从哪里开始呢?固然顶层的目次页少了,但是还要遍历啊?
不消担心,可以在加目次页

在查询的时间从最上面的Page开始,一个接一个的找到目次页。
从布局就可以看出,这就是B+树啊!没错,至此,我们已经给我们的表user构建完了主键索引。随便找一个id=?我们发现,如今查找的Page数一定镌汰了,也就意味着IO次数镌汰了,那么服从也就进步了。
复盘一下
Page分为目次页和数据页。目次页只放各个下级Page的最小键值。查找的时间,自定向下找,只需要加载部门目次页到内存,即可完成算法的整个查找过程,大大镌汰了IO次数
InnoDB
在建立索引布局来管理数据的时间,其他数据布局为何不行?


  • 链表?线性遍历?
    前文已经表明过,服从太慢
  • 二叉搜刮树?
    退化问题,可能退化成为线性布局
  • AVL &&红黑树?
    固然是均衡或者近似均衡,但是毕竟是二叉布局,相比力多阶B+,意味着树整体过高,各人都是自顶向下找,层高越低,意味着系统与硬盘更少的IO Page交互。固然你很秀,但是有更秀的。
  • Hash?
    官方的索引实现方式中,MySQL 是支持HASH的,不过InnoDB 和MyISAM 并不支持.Hash跟进其算法特征,决定了固然有时间也很快(O(1)),不过,在面临范围查找就显着不行,另外还有其他差别,有爱好可以查一下。
6. B+树 Vs B 树数

6.1 不同存储引擎支持的索引布局类型


数据布局演示链接:点击进入 里面有各种数据布局的布局。
6.2 B+树 Vs B树

B树?最值得比力的是InnoDB 为何不消B树作为底层索引?
B树

B+树

现在这两棵树,对我们最有意义的区别是:


  • B树节点,既有数据,又有Page指针,而B+,只有叶子节点有数据,其他目次页,只有键值和Page指针
  • B+叶子节点,全部相连,而B没有
为何选择B+
节点不存储data,如许一个节点就可以存储更多的key。可以使得树更矮,以是IO操作次数更少。叶子节点相连,更便于举行范围查找。
7. 聚簇索引 Vs 非聚簇索引

7.1 MyISAM Vs InnoDB

MyISAM 存储引擎—主键索引
MyISAM 引擎同样利用B+树作为索引效果,叶节点的data域存放的是数据纪录的地址。下图为表的主索引,Col1 为主键。

此中,MyISAM 最大的特点是,将索引Page和数据Page分离,也就是==叶子节点没有数据,只有对应数据的地址。相较于InnoDB 索引,InnoDB 是将索引和数据放在一起的。
MySAM存储引擎演示:
MySQL:
  1. --创建数据库
  2. create database myisam_test;
  3. use myisam_test;
  4. create table mtest(
  5. id int primary key,
  6. name varchar(11) not null
  7. )engine=MyISAM;              
  8. --使用engine=MyISAM
复制代码
Linux:
命令:ls /var/lib/mysql/myisam_test/ -al

MyISAM 这种用户数据与索引数据分离的索引方案,叫做非聚簇索引
Innodb存储引擎演示:
MySQL:
  1. --创建数据库
  2. create database Innodb_test;
  3. use Innodb_test;
  4. create table Itest(
  5. id int primary key,
  6. name varchar(11) not null
  7. )engine=Innodb;              
  8. --使用engine=Innodb
复制代码
Linux:
命令:ls /var/lib/mysql/myisam_test/ -al

InnoDB 这种用户数据与索引数据在一起索引方案,叫做聚簇索引
MySQL除了默认会建立主键索引外,我们用户也有可能建立按照其他列信息建立的索引,一样平常这种索引可以叫做辅助(平凡)索引。
对于M yISAM ,建立辅助(平凡)索引和主键索引没有差别,无非就是主键不能重复,而非主键可重复。
下图就是基于MyISAM 的Col2 建立的索引,和主键索引没有差别

同样,InnoDB 除了主键索引,用户也会建立辅助(平凡)索引,我们以上表中的
Col3 建立对应的辅助索引,如下图:

可以看到,InnoDB 的非主键索引中叶子节点并没有数据,而只有对应纪录的key值。
以是通过辅助(平凡)索引,找到目标纪录,需要两遍索引:起首检索辅助索引获得主键,然后用主键到主索引中检索获得纪录。这种过程,就叫做回表查询
为何InnoDB 针对这种辅助(平凡)索引的场景,不给叶子节点也附上数据呢?
答:太浪费空间了。目次Page就全部存放目次,如许才是最大的优化。
7.2 总结

InnoDB 主键索引和平凡索引
答:


  • 主键索引在 InnoDB 中是聚簇索引,这意味着数据行的物理存储序次与主键的序次一致。如果没有显式定义主键,InnoDB 会选择第一个非空的唯一索引作为聚簇索引。如果没有合适的唯一索引,InnoDB 会建一个隐藏的聚簇索引。
  • 辅助索引的叶子节点存储的是主键值,而不是数据行的物理地址。
    通过辅助索引查找数据时,起首找到主键值,然后通过主键值在聚簇索引中找到数据行。
MyISAM 主键索引和平凡索引
答:


  • 主键索引和平凡索引在 MyISAM 中都是非聚簇索引,这意味着索引的叶子节点存储的是数据行的物理地址。主键索引和平凡索引在布局上没有区别,只是主键索引是唯一的。
  • 平凡索引的叶子节点存储的是数据行的物理地址。通过索引查找数据时,直接根据物理地址访问数据行。
其他数据布局为何不能作为索引布局,尤其是B+和B
B+ 树的优势


  • 高效的范围查询:
    B+ 树的叶子节点是链表情势连接的,这使得范围查询非常高效。
    在举行范围查询时,可以从一个叶子节点开始,沿着链表快速遍历多个节点。
  • 较高的扇出(Fan-out):
    B+ 树的每个节点可以容纳更多的键值,因此树的高度较低,镌汰了磁盘 I/O 次数。
    较低的树高度意味着更快的查询速度。
  • 稳固的性能:
    B+ 树的插入和删除操作复杂度为 O(log n),性能稳固。
    插入和删除操作不会导致树的高度变化,保持了查询性能的稳固性。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

农民

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表