四步趟过MySQL之第一步:MySQL架构学习

632 阅读8分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第1天,点击查看活动详情

本次学习总结基于大版本5.7的MySQL,学习重点为InnoDB引擎。

一、MySQL执行SQL语句的流程

QQ截图20220802201219.png

1.1 连接层:管理控制连接

不管通过什么方式和MySQL进行交互,首先都需要建立客户端与服务端连接,连接层就是负责控制连接和验证用户身份的

通信类型:同步/异步

连接方式:长连接/短连接

协议:TCP/Unix Socket(在linux本机客户端连本机服务端用的是这样一个文件)

因为Mysql是单进程多线程的模式工作的,客户端每产生一个连接服务端就会产生一个线程来处理这个连接;

怎么察看客户端维持了多少个跟客户端的连接?

show global status like 'Thread%';

image.png

5.7版本的MySQL服务默认允许的最大连接数(并发数)为151个,最大可设置为100000

show variables like 'max_connections';

1.2 缓存(没啥用的玩意)

MySQL自己的缓存默认不开启,局限性太大,sql变了一点就识别不出来,一般项目中结合Mybatis处理缓存。

1.3 解析器

包含解析器和预处理器

解析器:

  • 高情商: 解析器负责对输入的语句基于SQL语法进行词法的分析和语义的解析,解析通过后生成解析树(select_lex)。

  • 低情商: MySQL先给你检查下你的SQL语法写的对不对啊,“select”是不是写成了"sleect",几个关键字的顺序用的对不对啊之类的。

预处理器:

  • 高情商: 接到解析器生成的解析树后,继续解析解析器无法解析的语义,预处理后得到一个新的解析树。

  • 低情商: 接着检查你写的表名、列名是否有歧义,写没写错,是否有歧义?

1.4 优化器

根据解析树生成不同的执行计划,然后选择最优的(开销小的)计划

一条SQL可能会有多种执行方式,优化器的目的就是根据解析树生成不同的执行计划,然后选择最优的(开销小的)计划

可以通过在SQL前加EXPLAN来查看执行计划

如果想看详细的情况,在EXPLAN后边加上FORMAT=JSON,或者开启optimizer trace。

1.5 存储引擎

创建表的时候通过ENGINE关键字指定,后期可修改,5.5.5之前默认是MyISAM,5.5.5之后默认为InnoDB。

image.png

1.6 查询SQL与更新SQL

查询没啥好说的,按照流程一步步走下去,将结果返回就完了;

更新SQL找到要操作的数据和查询基本一致,区别在于拿到数据之后的处理操作;

简化版更新过程:

1、事务开始,从内存(buffer pool)或磁盘(data file)取到包含这条数据的数据页,返回给Server的执行器;
2、Server 的执行器修改数据页的这一-行数据的值为 penyuyan;
3、记录name=qingshan到undo log;
4、记录name=penyuyan到redo log; .
5、调用存储引擎接口,记录数据页到Buffer Pool (修改name=penyuyan) 
6、事务提交。

名词解释:

1、缓冲池:Buffer Pool(为了提升读写的效率)

对于InnoDB存储引擎来讲,数据都是放在磁盘上的,存储引擎要操作数据,必须先把磁盘里面的数据加载到内存里才能操作,但是由于和磁盘进行IO操作要经过寻址能一系列操作,导致效率很慢,所以就不能需要多少数据就拿多少数据——预读取机制(一次读一页,操作系统的一页大小一般是4k,InnoDB里,默认最小16KB)

修改数据的时候也是先写入到Buffer Pool里,当内存里的数据页和磁盘数据不一致的时候,叫脏页,InnoDB中有专门的后台线程来完成数据同步,这个动作叫刷脏。

2、Redo Log(重做日志)(为了解决在BufferPool中的数据还没刷入磁盘中,服务器/数据库就断电或宕机导致数据丢失——ACID-D-事务的持久性)

为啥加它对性能影响比较小?数据直接写入磁盘文件需要有一个寻址的过程,所以慢,而RedoLog记录日志不需要一次次寻址,直接写就行(连续写入)(顺序IO和随机IO区别)

3、Undo Log(撤销日志/回滚日志)(记录了事务发生之前的数据状态,分为Insert undolog和update underlog)如果修改数据时出现了异常,可以用undolog来实现回滚操作-事务的原子性)

记录的是反向操作,insert会记录delete,update会记录update原来的值,

redo Log 和undo Log与事务密切相关,统称为事务日志。

二、InnoDB架构分析

image.png

2.1 内存结构

2.1.1 BufferPool

缓冲池介绍在上边名词解释中有,不再赘述。

缓冲池缓存的是页面信息,包括数据页、索引页,默认大小128M,强烈建议调大。能尽可能的提升数据库运行效率。

缓冲池知识点附加:LRU算法

缓冲池中的数据页并不都是在访问过之后才缓存到缓冲池中的,InnoDB有一个预读机制(设计者认为你访问某个page之后可能会接着访问相邻的page,所以就把相邻的page也放进来了)

缓冲池那么好用,但是总归有尽头,这时候就需要有一个淘汰机制——LRU算法; InnoDB在传统LRU的结构基础上(Map+链表),将链表部分分为new区和old区(冷热分离)。

image.png

默认情况下热区占5/8,冷区占3/8;

规则:

1.所有新数据加入到buffer pool的时候,一律先放到old区的head,不管是预读的还是普通读的;

2.old区的数据被访问到,会将其移动到new区的head,new区原有数据如果长时间没有被访问,会被先移动到old区中的head,直到慢慢从tail淘汰;

3.为了防止很多只用一次的数据大批量进入new区,导致原有的热点数据被挤跑,有一个默认1秒的时间窗口,只有进入到old区1秒中后又被访问的才从old移动到new区的head;

4.为了防止new区过于频繁的移动增加不必要的开销,如果一个页处于new区的前1/4区域,那么当访问这个页的时候,就不用将其移动到new区的head,只有当页位于new区的后3/4区域中时,被访问的时候才会将其移动到new区的head;

2.1.2 Log Buffer

Log Buffer是redo log的写缓冲,默认16m。

数据库中的数据是从Buffer Pool中写入磁盘文件,Redo Log通过Log Buffer写入特定磁盘文件。

Log Buffer写入时机通过"innodb_flush_log_at_trx_commit"来控制,默认参数1

image.png

2.2 磁盘结构

2.2.1 系统表空间

包含InnoDB数据字典、双写缓冲区、ChangeBuffer和UndoLogs,如果没有指定file-per-table,系统表空间中也包含用户创建的表和索引数据

双写缓冲区

InnoDB的页和操作系统的页大小不一致, InnoDB页大小一般为16K,操作系统页大小为4K, InnoDB的页写入到磁盘时,一个页需要分4次写。如果存储引擎写到一页中的一部分时系统宕机了,可能会导致数据丢失。

正常情况下的崩溃恢复可以使用redo log,doublewrite就是保证了只写入部分页情况下的崩溃恢复。

InnoDB通过redo log和 doublewrite共同实现事务的持久性。

2.2.2 Binlog

以事件的形式记录了所有的DDL和DML语句(因为它记录的是操作而不是 数据值,属于逻辑日志),可以用来做主从复制和数据恢复。

在开启了binlog功能的情况下,我们可以把binlog导出成SQL语句,把所有的操作重放一遍,来实现数据的恢复。

开启binlog后,更新操作变为二段式提交

例如一条语句: 
update teacher set name= '盆鱼宴' where id=1;
1、先查询到这条数据,如果有缓存,也会用到缓存。
2、把name改成盆鱼宴,然后调用引擎的API接口,写入这一行数据到内存,同时记录redo log。这时redo log进入prepare状态,然后告诉执行器,执行完成了,可以随时提交。
3、执行器收到通知后记录binlog,然后调用存储引擎接口,设置redo log为commit状态。
4、更新完成。

在崩溃恢复时,判断事务是否需要提交:

1、binlog无记录,redolog 无记录:在redolog写之前crash,恢复操作:回滚事务

2、binlog 无记录,redolog 状态prepare:在binlog写完之前的crash,恢复操作:回滚事务

3、binlog 有记录,redolog 状态prepare:在binlog写完提交事务之前的crash,恢复操作:提交事务

4、binlog 有记录, redolog 状态commit:正常完成的事务,不需要恢复