Mysql的架构

2023-11-16

文章学习自互联网以及小林Coding,侵删! 下面先进行快速回顾概念,然后再进行学习Mysql的架构

一、什么是数据库(DataBase)

数据库是所有软件体系中最核心的存在,作用:1. 存储数据 2. 管理数据

开源的Mysql直接用500万以下的数据都没有问题之后就需要优化!

  • 数据库(Database) :存储的数据的集合,提供数据存储的服务
  • 数据(Data) :实际上指的是描述事物的符号记录
  • 数据库管理系统(Database Management System,DBMS ) : 数据库管理系统,是位于⽤户与操作系统之间的⼀层数据管理软件
  • 数据库系统管理员(Database Anministrator,简称为DBA) :负责数据库创建、使⽤及维护的专⻔⼈员
  • 数据库系统(Database System,DBS) :数据库系统管理员、数据库管理系统及数据库组成整个单元

二、MySQL架构(Server层+存储引擎层)

MySQL架构图如下:
在这里插入图片描述
来自小林大佬画的图,很清楚可以看到分为server层存储引擎层
Server 层负责建立连接、分析和执行 SQL;
存储引擎层负责数据的存储和提取,默认为InnoDB,默认索引类型是 B+树。

1、一条SQL语句的执行过程(server层)

第一步:连接器
MySQL 客户端与服务器间进行 TCP 三次握手建立连接;
服务端校验客户端的用户名和密码,如果用户名或密码不对,则会报错;
如果用户名和密码都对了,会读取该用户的权限,然后后面的权限逻辑判断都基于此时读取到的权限;

注意定期断开长连接避免内存占用,最大连接用户限制默认151,空闲连接超过默认时间连接器自动断开

第二步: 查询缓存
连接成功,接收SQL语句,查看类型若为查询语句就在缓存中查找之前是否有缓存执行过这条语言的数据,如果有就直接返回,没有就继续执行,待执行完之后,查询语句与执行结果以key-value的形式加入缓存;

由于只要有一个表有更新操作,查询缓存就会被清空,对于更新比较频繁的情况下这个功能几乎无用且耗时,所以MySQL8.0开始就移除了server层的查询缓存。注意:Innodb 存储引擎中的 buffer pool并没有移除

第三步: 解析器
解析SQL语句,先进行词法分析,识别出关键字构建SQL语法树,然后进行语法分析,判断是否满足SQL语法,如果关键字错误,或者语法错误这里就会报错并返回。

这里只进行词法和语法分析,表或字段是否存在?这里并不判断

第四步:执行器
根据解析器生成的语法树,进行以下三步走执行:
预处理阶段(prepare)–> 优化阶段(optimize )–> 执行阶段(execute)

预处理阶段
检查 SQL 查询语句中的表或者字段是否存在;如果不存在返回报错
将 select * 中的 * 符号,扩展为表上的所有列;
优化阶段
基于查询成本考虑选择SQL语句的执行方案,比如在表里面有多个索引的时候使用什么索引?
最低效的就是全表扫描。优化可能为主键索引等
执行阶段
根据执行计划执行 SQL 查询语句,从存储引擎读取记录,返回给客户端;


这个时候再来回顾一下这个图就很清楚了,小林coding的图解MySQL讲的很详细了
在这里插入图片描述

2、一条记录是怎么存储的(存储引擎层)

MySQL的数据由存储引擎实现保存在磁盘上的,InnoDB是默认也是常用的存储引擎,用SHOW VARIABLES LIKE 'datadir';可以查看MySQL数据库文件存储的目录,每创建一个数据库,这里就会多一个以该数据库名的目录,目录下的三个文件,分别为:

  • .opt的后缀文件存储当前数据库的默认字符集和字符校验规则

  • .frm的后缀文件存储对应表的表结构,保存每个表的元数据信息

  • .ibd的后缀文件存储对应表的表数据表,默认每张表存放在一个独占表空间文件

表空间由段(segment)、区(extent)、页(page)、行(row)组成,InnoDB存储引擎的逻辑存储结构大致如下图:
在这里插入图片描述
数据库表中的记录都是按行(row)进行存放的,每行记录根据不同的行格式,有不同的存储结构。
InnoDB 的数据是按「页」为单位来读写的,也就是说,当需要读一条记录的时候,并不是将这个行记录从磁盘读出来,而是以页为单位,将其整体读入内存。默认每个页的大小为 16KB

总之,数据库表中的记录按行存储在「数据页」里

一行数据的存储结构即行格式,行格式有几种,一种通其他皆会,小林这里讲的是Compact 行格式如下:
在这里插入图片描述
这段有点迷,先挖个坑在这,先看看一些问题的答案:
1、varchar(n) 中 n 最大取值为多少?
一行记录最大能存储 65535 字节的数据,但是这个是包含「变长字段字节数列表所占用的字节数」和「NULL值列表所占用的字节数」。所以, 我们在算 varchar(n) 中 n 最大值时,需要减去这两个列表所占用的字节数。

如果一张表只有一个 varchar(n) 字段,且允许为 NULL,字符集为 ascii。varchar(n) 中 n 最大取值为 65532。

计算公式:65535 - 变长字段字节数列表所占用的字节数 - NULL值列表所占用的字节数 = 65535 - 2 - 1 = 65532。

如果有多个字段的话,要保证所有字段的长度 + 变长字段字节数列表所占用的字节数 + NULL值列表所占用的字节数 <= 65535。

2、行溢出后,MySQL 是怎么处理的?
如果一个数据页存不了一条记录,InnoDB 存储引擎会自动将溢出的数据存放到「溢出页」中。如下图
在这里插入图片描述
3、MySQL 的 NULL 值是怎么存放的?
MySQL 的 Compact 行格式中会用「NULL值列表」来标记值为 NULL 的列,NULL 值并不会存储在行格式中的真实数据部分。

NULL值列表会占用 1 字节空间,当表中所有字段都定义成 NOT NULL,行格式中就不会有 NULL值列表,这样可节省 1 字节的空间。

4、MySQL 怎么知道 varchar(n) 实际占用数据的大小?
MySQL 的 Compact 行格式中会用「变长字段长度列表」存储变长字段实际占用的数据大小。


三、深入存储引擎层理解

https://zhuanlan.zhihu.com/p/430429017
除了参考上面知乎内容还看了另一篇文章的,好像是小牛肉的,都是很不错的文章!!!

innoDB 存储引擎由内存池和一些后台线程组成,下图为InnoDB的内存结构和磁盘结构
在这里插入图片描述

1、内存池(缓冲池)

先来解释下内存池。

首先,我们需要知道,InnoDB 存储引擎是基于磁盘存储的,并将其中的记录按照的方式进行管理。因此可将其视为基于磁盘的数据库系统(Disk-base Database),在这样的系统中,众所周知,由于 CPU 速度与磁盘速度之间的不匹配,通常会使用缓冲池技术来提高数据库的整体性能。

所以这里的内存池也被称为缓冲池(简单理解为缓存就好了)。

具体来说,缓冲池其实就是一块内存区域,在 CPU 与磁盘之间加入内存访问,通过内存的速度来弥补磁盘速度较慢对数据库性能的影响。

拥有了缓冲池后,“读取页” 操作的具体步骤就是这样的:

  • 首先将从磁盘读到的页存放在缓冲池中
  • 下一次再读相同的页时,首先判断该页是否在缓冲池中。若在缓冲池中,称该页在缓冲池中被命中,直接读取该页。否则,读取磁盘上的页。

“修改页” 操作的具体步骤就是这样的:

  • 首先修改在缓冲池中的页;然后再以一定的频率刷新到磁盘上。

所谓 ”脏页“ 就发生在修改这个操作中,如果缓冲池中的页已经被修改了,但是还没有刷新到磁盘上,那么我们就称缓冲池中的这页是 ”脏页“,即缓冲池中的页的版本要比磁盘的新。

至此,综上所述,我们可以得出这样的结论:缓冲池的大小直接影响着数据库的整体性能

Buffer Pool缓冲池

innordb基于磁盘存储的,其中的记录以的方式进行管理,缓解 CPU 与磁盘速度之间的矛盾,基于磁盘的数据库系统通常使用缓冲池技术来提高数据库的整体性能

Checkpoint 的机制来决定哪些数据该从缓冲池移出去(移到磁盘上)

Innodb 存储引擎设计了一个缓冲池(*Buffer Pool*),来提高数据库的读写性能。

Buffer Pool 以页为单位缓冲数据,可以通过 innodb_buffer_pool_size 参数调整缓冲池的大小,默认是 128 M。

Innodb 通过三种链表来管理缓页:

  • Free List (空闲页链表),管理空闲页;
  • Flush List (脏页链表),管理脏页;
  • LRU List,管理脏页+干净页,将最近且经常查询的数据缓存在其中,而不常查询的数据就淘汰出去。;

InnoDB 对 LRU 做了一些优化,我们熟悉的 LRU 算法通常是将最近查询的数据放到 LRU 链表的头部,而 InnoDB 做 2 点优化:

  • 将 LRU 链表 分为young 和 old 两个区域,加入缓冲池的页,优先插入 old 区域;页被访问时,才进入 young 区域,目的是为了解决预读失效的问题。
  • 当**「页被访问」且「 old 区域停留时间超过 innodb_old_blocks_time 阈值(默认为1秒)」**时,才会将页插入到 young 区域,否则还是插入到 old 区域,目的是为了解决批量数据访问,大量热数据淘汰的问题。

可以通过调整 innodb_old_blocks_pc 参数,设置 young 区域和 old 区域比例。

在开启了慢 SQL 监控后,如果你发现「偶尔」会出现一些用时稍长的 SQL,这可因为脏页在刷新到磁盘时导致数据库性能抖动。如果在很短的时间出现这种现象,就需要调大 Buffer Pool 空间或 redo log 日志的大小。

Insert Buffer 插入缓冲

索引的本质是什么?是 B+ 树,是一个存在磁盘上的物理文件。那我们在构建辅助索引 username 的这棵 B+ 树的时候,非聚集索引叶子节点的插入不再是顺序的了,也就是说要去离散地访问磁盘页了。正是由于随机读取的存在导致了插入操作性能下降

InnoDB 存储引擎开创性地设计了 Insert Buffer。对于辅助索引的插入或更新操作,并不是每一次直接插入到索引页(磁盘页)中,而是先判断插入的辅助索引页是否在 Buffer Pool 中。若需要实现插入记录的辅助索引页不在 Buffer Pool 中,那么就将这个操作首先记录到 Insert Buffer 中,然后在适当的情况下将其合并(Merge)到真正的辅助索引中。

个人理解就是插入数据时候,聚集索引一般建立在主键上面,插入聚集索引一般是顺序的,不需要经过磁盘的随机读取。但是要是若有不是顺序的辅助索引,这个时候插入的辅助索引页就需要进行访问磁盘页,就会导致性能变慢。Innodb就弄了个插入缓冲池,先放到这个里面会以一定的频率和情况,将 Insert Buffer 中的操作应用到原数据页,就像你还了一本书,图书管理员不会去立刻归位,而是以一定的频率和具体情况把这些归还在柜台的书一起分类归位,这样就减少了很多跑来跑去的时间。

2、后台线程

后台线程的主要作用就是刷新内存池中的数据,保证内存池中缓存的是最近的数据;此外将已修改的数据文件刷新到磁盘文件,同时保证在数据库发生异常的情况下 InnoDB 能恢复到正常运行状态。

主要作用:“将从磁盘读到的页存放在缓冲池中” 以及 “将缓冲池中的数据以一定的频率刷新到磁盘上

redo log(重写日志) 与 WAL (write ahea log)策略

当缓冲池中的某一页的数据被修改就会被标记为脏页,脏页的数据会定期刷新到磁盘,如果从缓冲池刷新到磁盘发生宕机,那么这个数据就不能恢复了。为了避免发生数据丢失的问题,MySQL的事务数据库系统普遍采用WAL(Write Ahead Log预写日志)策略。当事务提交时,先写重做日志(redo log),再修改页(先修改缓冲池,再刷新到磁盘);当由于发生宕机而导致数据丢失时,通过 redo log 来完成数据的恢复

每个 InnoDB 存储引擎至少有 1 个重做日志文件组( redo log group),每个文件组下至少有 2 个重做日志文件(redo log file),默认的话是一个 redo log group,其中包含 2 个 redo log file:ib_logfile0ib_logfile1

一般来说,为了得到更高的可靠性,用户可以设置多个镜像日志组(mirrored log groups),将不同的文件组放在不同的磁盘上,以此提高 redo log 的高可用性。在日志组中每个 redo log file 的大小一致,并以循环写入的方式运行。

  • redo log file 不能设置得太大,如果设置得很大,在恢复时可能需要很长的时间
  • redo log file 又不能设置得太小了,否则可能导致一个事务的日志需要多次切换重做日志文件

CheckPoint 技术

redo log和缓冲池内存有限,如果数据库运行了很久,这个时候发生宕机,恢复代价非常大,所以引入checkpoint来解决问题

  • 缓冲池不够用时,将脏页刷新到磁盘
  • redo log 不可用时,将脏页刷新到磁盘
  • 缩短数据库的恢复时间

所谓 CheckPoint 技术简单来说其实就是在 redo log file 中找到一个位置,将这个位置前的页都刷新到磁盘中去,这个位置就称为 CheckPoint(检查点)。

。。。

MySQL 架构可以分成俩层,一层是 Server 层,它主要做的是 MySQL 功能层面的事情;另一层就是存储引擎,负责存储与提取相关的具体事宜。

redo log 是 InnoDB 引擎特有的日志,而 Server 层也有自己的日志,包括错误日志(error log)、二进制日志(binlog)、慢查询日志(slow query log)、查询日志(log)。

其他三个日志顾明思意都挺好理解的,需要解释的就是 binlog(二进制日志,binary log),它记录了对 MySQL 数据库执行更改的所有操作,但是不包括 SELECTSHOW 这类操作,因为这类操作对数据本身并没有修改。也就是说,binlog 是逻辑日志,记录的是这个语句的原始逻辑,比如 “给 ID=1 这一行的 a 字段加 1”。

可以看出来,binlog 日志只能用于归档,因此 binlog 也被称为归档日志,显然如果 MySQL 只依靠 binlog 等这四种日志是没有 crash-safe 能力的,所以为了弥补这种先天的不足,得益于 MySQL 可插拔的存储引擎架构,InnoDB 开发了另外一套日志系统 — 也就是 redo log 来实现 crash-safe 能力。

这就是为什么有了 bin log 为什么还需要 redo log 的答案。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Mysql的架构 的相关文章

随机推荐

  • C++ map::begin()、end()

    在C 中 std map是一个关联容器 它提供了一种键 值对的存储方式 并按照键的排序顺序进行自动排序 map类提供了一系列的成员函数 其中包括begin 和end 函数 用于获取指向map容器中第一个元素和最后一个元素之后位置的迭代器 下
  • RPC与Netty简介

    RPC 一 Socket介绍 Socket概述 Socket 套接字就是两台主机之间逻辑连接的端点 TCP IP协议是传输层协议 主要解决数据如何在网络中传输 而HTTP是应用层协议 主要解决如何包装数据 Socket是通信的基石 是支持T
  • JsRPC技术介绍及服务搭建

    声明 本文章中所有内容仅供学习交流 不可用于任何商业用途和非法用途 否则后果自负 如有侵权 请联系作者立即删除 由于本人水平有限 如有理解或者描述不准确的地方 还望各位大佬指教 前言 Js Rpc意思就是远程调用js代码 全称 Remote
  • 13.1 二次型Quadratic Form

    文章目录 曲面 定义 举例 曲面 曲面是非常值得研究的 在制造业中 曲面尤其重要 所以我们先从曲面开始 比如以下曲面 它的方程是 z 3 x 2
  • Linux上Redis的启动、使用和停止

    0 安装Redis参考06003 redis在Linux上的安装 1 Redis的启动 1 前端模式启动 直接运行bin redis server将以前端模式启动 切换到 usr local redis redis bin目录下 然后 re
  • C/C++

    文章目录 VSCode中C编译环境配置 MinGW gcc 操作系统 win10专业版 64位 待安装的软件及工具 1 安装VSCode 2 安装C C 插件 执行代码 停止代码运行 Code Runner配置方法 3 下载及安装MinGW
  • 构造函数和工厂函数学习笔记

    之前对构造函数和工厂函数有一定的困扰 究竟什么是工厂函数什么才算是构造函数 在网上查了他两的区别后发现大多数讲的都不尽人意 可以说是越看越懵 后来被我们老大看到了 很有意思的说 这个他们说的都不是那么一回事 算了我来和你讲吧 我问你 工厂主
  • 【猿人学WEB题目专解】猿人学第1题

    据说 看我文章时 关注 点赞 收藏 的 帅哥美女们 心情都会不自觉的好起来 前言 作者简介 大家好我是 user from future 意思是 来自未来的用户 寓意着未来的自己一定很棒 个人主页 点我直达 在这里肯定能找到你想要的 专栏介
  • Openerp权限设置总结

    主要对模块下的security 目录下的文件 xxx security xml ir model access csv进行讲解 xxx security xml 1 建立组
  • python3通过pymysql连接MySQL数据库操作

    python连接MySQL数据库 所需要的工具 PyCharm pymysql插件 MySQL数据库 安装pymysql插件 在PyCharm中依次点击file gt setting gt project xxx gt project in
  • 一个简单的会先客户端/服务器应用

    不管服务器从客户端收到什么输入 都会将其回显出来 在命令行中指定TCP接口 几个注意的地方 要使用socket error要记得提前导入 from socket import error 用docopt从命令行中取得端口号 这是字符串类型的
  • 【Qt】运行py加载ui文件,顶层窗口的背景、布局等样式失效(与预览不同),或特定对象和布局无法显示(包括代码生成)

    目录 一 问题 情况 二 一些解决方法 0 分辨率 屏幕适配问题 1 运行环境问题 三 通用解决方法 更新 方法更高效耶 一 问题 情况 遇到的问题 1 运行py文件 代码中通过加载ui文件 设置为顶层窗口 运行结果与预览不同 窗口样式失效
  • 使用python读取和保存为excel、csv、txt文件以及对DataFrame文件的基本操作

    文章目录 一 对excel文件的处理 1 读取excel文件并将其内容转化DataFrame和矩阵形式 2 将数据写入xlsx文件 3 将数据保存为xlsx文件 4 使用excel对数据进行处理的缺点 二 对csv文件的处理 1 读取csv
  • adb shell 小米手机_小米手机ADB删除系统应用去广告。

    小米手机ADB删除系统应用去广告 前言 1 准备 2 进入开发者模式 3 连接手机与电脑 4 使用ADB命令删除系统应用 本文要介绍的方法可以免 root 卸载预置应用 仅删除当前用户下的 APP 不是彻底删除 APP 恢复出厂设置后 删除
  • mysql 子查询(七)之子查询排序

    大多数子查询不需要排序 没有意义 因为子查询大多数是作为一个结果或参数给主查询使用 但top n问题除外 举个例子 查询员工表中 行政部 的员工 select from emp where empdetno select empdetno
  • 一种为polar code简化的sc译码

  • 业绩归因 绩效评估 - 各种收益率计算方法

    收益率计算 1 定义 1 1 日收益率 收 益 率 收 益 额
  • echarts默认显示一个时间点的tooltip以及鼠标移出之后依然显示 tooltip

    最终显示效果如下 默认打开页面显示设置的某个时间点的tooltip 鼠标移开之后依然显示 下面是实现代码 一看就懂 搬走就用 draw tabIndex let pricetrend this echarts getInstanceByDo
  • 280个ai网站导航vs500+ai工具集导航,到底哪一个好?

    最值得收藏的AI工具 让你生产力爆表 效率无敌 简洁猫AI网站导航 包含了 包含但不限于 ChatGPT Midjourney 阿里云AI学习路线 金山快译 酷表ChatExcel 通义千问 通义万相 达摩院 讯飞 触手AI 腾讯智影 腾讯
  • Mysql的架构

    目录 一 什么是数据库 DataBase 二 MySQL架构 Server层 存储引擎层 1 一条SQL语句的执行过程 server层 2 一条记录是怎么存储的 存储引擎层 三 深入存储引擎层理解 1 内存池 缓冲池 Buffer Pool