Mysql原理系列篇 第一章 1条语句的执行
文章目录
- Mysql原理系列篇 第一章 1条语句的执行
- 前言:
- 1 连接mysql 服务端:
- 1.1 通信模型:
- 1.2 通信连接数:
- 2 sql 语句的到达存储引擎的流程:
- 3 数据从存储引擎返回的流程:
- 4 Buffer_pool 脏页的刷脏:
- 4.1 刷脏的机制:
- 4.2 脏页数据丢失问题:
- 4.2 redolog 作用:
- 4.3 Buffer_pool 内存回收:
- 5 Mysql 的 binlog日志:
- 5.1 binlog 作用:
- 5.2 binlog 和redo log 为什么同时存在:
- 6 binlog 和 redo log的协同工作:
- 6.1 工作流程:
- 6.2 崩溃恢复:
- 7 Mysql 的 undolog日志:
- 7.1 undolog 作用:
- 7.2 undolog 回滚机制:
- 7.2.1 undlog 日志格式:
- 7.2.2 一条数据多次更新 undlog 日志记录:
- 7.3 undolog 怎么区分不同的事务:
- 7.4 undolog 大小和清理规则:
- 7.5 undolog 被占用完会发生什么:
- 7.5 开启事务后一条sql 的执行流程:
- 7.5 buffer pool 中的定时刷盘任务 对于尚未提交事务的sql 处理:
- 7.6 undolog,redolog ,binlog 和buffer pool 的写入顺序:
- 总结
前言:
对于mysql 数据存储工具,我们并不陌生,但是当我去执行1条sql 语句时,mysql 执行的流程是怎样的;
1 连接mysql 服务端:
1.1 通信模型:
服务实际上提供了多种通信的模型,可以适应不同的客户端连接到服务端;我们经常使用的是同步,tcp长连接的方式进行接入;
1.2 通信连接数:
客户端与服务端建立连接的数量并不是无限的,默认情况下,所有客户端共享默认的151
个连接;如果超出最大连接,MySQL 服务器可以将新的连接请求放入一个等待队列中
。等待队列中的连接请求将按照先进先出(FIFO
)的顺序进行处理。一旦有一个连接释放出来,MySQL 服务器就会将等待队列中的下一个连接请求分配连接资源,并建立新的连接。
MySQL 服务器会对空闲连接进行超时处理,以释放连接资源。连接超时的时间由配置参数 wait_timeout
控制,默认为8
小时。当连接空闲时间超过 wait_timeout 的设定值后,MySQL 服务器会自动关闭该连接,并释放相关的资源.
通常我们可以通过调整 max_connections
(最大值100000)参数来增加最大连接数:
2 sql 语句的到达存储引擎的流程:
- 解析器:词法解析: 解析每个单词必须正确;语法解析:解析句子整体语法必须正确;语义解析:解析句子整体语义必须正确;
- 语句优化: 将sql 语句进行相应优化,如:去除多余的嵌套层;
- 执行计划:生成多个执行计划;
- 执行器: 得到最终的一个执行计划,然后交由存储引擎执行;
- 存储引擎:执行sql(不一定按照执行计划 执行sql);
3 数据从存储引擎返回的流程:
- 存储引擎从磁盘获取数据,按照page 页进行加载,每个page 页为16k,将加载到的数据缓冲到Buffer_pool 内存中;
- 如果是select:查询执行引擎负责执行查询计划,处理数据的过滤、聚合、排序等操作并将结果返回给 MySQL 服务器;
- 如果是更新操作(包括update insert delete):则从加载到Buffer_pool 对应的数据,进行修改,修改完成后通过存储引擎将修改后的数据存入到Buffer_pool 内存中;
- 位于Buffer_pool 内存中的更新数据会有后台线程定期还行,将数据刷到磁盘中;
4 Buffer_pool 脏页的刷脏:
4.1 刷脏的机制:
在缓冲池中进行数据的修改和处理后,并不立即写回到磁盘中。InnoDB 存储引擎会利用一种称为“脏页(Dirty Page)”的机制,将更新的数据页标记为脏页。然后,根据 InnoDB 的内部策略和算法,决定何时将脏页刷新回磁盘,这个过程称为“脏页刷新(Flush)”。
4.2 脏页数据丢失问题:
对于Buffer_pool 内存中的数据,如果出现mysql 服务宕机,其中的数据全部丢失,哪些来不及被刷到磁盘中的数据需要被保存;
redo log 日志:将还没有进行刷脏的更新数据,进行日志记录,当出现msyql宕机,当mysql 服务重启后从 redolog 中进行数据恢复,保证了内存数据的安全性,延迟刷盘时机,进而提升系统吞吐;
4.2 redolog 作用:
- 为InnoDB提供了崩溃恢复的特性,实现持久性;
- redo log记录的是“在某个数据页上做了什么修改”。属于物理日志;
- redo log的大小是固定的,前面的内容会被覆盖,一旦写满,就会触发buffer pool到磁盘的同步,以便腾出空间记录后面的修改;
- Redo Log的循环使用:Redo Log是循环使用的,意味着当Redo Log写满时,会从头开始覆盖之前的Redo Log数据。在进行循环时,需要确保Checkpoint位置之前的Redo Log数据已经被持久化,以免丢失一致性;
4.3 Buffer_pool 内存回收:
Buffer Pool的内存回收是指在MySQL中管理Buffer Pool的内存空间时,对不再需要的数据页进行回收释放。
MySQL的InnoDB存储引擎使用LRU(Least Recently Used)算法来管理Buffer Pool中的数据页。LRU算法通过维护一个链表,将最近访问的数据页放在链表的前端,而较久未被访问的数据页则放在链表的后端。
当Buffer Pool中的内存空间不足时,InnoDB存储引擎会根据LRU算法,从链表的末端开始,逐渐将较久未被访问的数据页从Buffer Pool中移除,以腾出更多的空间给其他数据页使用。被移除的数据页可能会写回到磁盘中(如果它们是脏页并且是更新操作),或者直接丢弃。
此外,InnoDB还支持一种称为"Adaptive LRU"的机制,它可以动态调整LRU算法的行为。Adaptive LRU根据系统访问模式和数据页使用频率的变化,自动调整链表中的热点数据页位置,以提高缓存命中率。
需要注意的是,Buffer Pool的内存回收是自动进行的,通常由后台线程负责管理。MySQL DBA和开发人员可以通过配置参数来调整Buffer Pool的大小,以适应不同的工作负载需求。
5 Mysql 的 binlog日志:
5.1 binlog 作用:
Binlog是用于记录MySQL服务器上的所有数据更改操作,包括对表结构的更改。Binlog记录了数据库中所有的操作语句,以及这些操作在执行时的上下文信息。Binlog是MySQL服务器层的一个组件,并不依赖于具体的存储引擎。通过读取Binlog,可以重放数据更改操作,进行数据恢复、复制、备份、查找历史数据等操作;
5.2 binlog 和redo log 为什么同时存在:
-
持久性和事务恢复:Redo Log用于保证事务的持久性,能够在数据库崩溃或断电等故障时进行事务恢复。它只记录InnoDB存储引擎的数据修改操作。Redo Log是物理日志,主要目的是对数据进行恢复。
-
数据复制和高可用:Binlog则用于实现数据复制和高可用性。通过读取Binlog中的数据变更操作,可以在其他MySQL实例上重放这些操作,从而实现数据的复制和同步。Binlog是逻辑日志,主要目的是对操作进行复制和恢复。
-
Redo Log 主要用于存储Buffer Pool 来不及存入磁盘的数据,提供mysql 宕机后的数据恢复,Redo Log的文件是有大小的,而且数据会被清理;
-
binlog 记录的是执行的操作语句,内容是不会被删除的,所以可以用作mysql的 主从复制;
6 binlog 和 redo log的协同工作:
6.1 工作流程:
- 要想操作数据,需要存储引擎向将数据按页加载到 pool buffer 中;
- 修改数据;
- 将数据存回到pool buffer;
- 记录redolog 日志方式数据丢失,二阶段提交记录数据 为prepare;
- 记录binlog dml 语句;
- 提交事务;
- 将redolog 数据标记为commit;
6.2 崩溃恢复:
redolog 二阶段提交保证 redolong 和binlog 保持一致;在崩溃恢复时,判断事务是否需要提交:
- binlog无记录,redolog无记录 情况:
在redolog写之前crash,恢复操作: 回滚事务 - binlog无记录,redolog状态prepare 情况:
在binlog写完之前的crash,恢复操作: 回滚事务 - binlog有记录,redolog状态prepare 情况:
在binlog写完提交事务之前的crash,恢复操作:提交事务 - binlog有记录,redolog状态commit 情况:
正常完成的事务,不需要恢复
7 Mysql 的 undolog日志:
7.1 undolog 作用:
MySQL中的Undo Log(回滚日志)是与事务相关的一种日志,用于回滚(撤销)事务对数据库的修改操作。Undo Log记录了事务执行过程中对数据做的修改操作,包括插入、更新和删除等操作,在事务回滚时使用这些日志进行撤销,将数据恢复到事务开始之前的状态。
Undo Log有以下几个主要的作用:
-
回滚:当事务执行过程中发生错误或者回滚操作时,Undo Log中记录的操作可以用于将数据恢复到之前的状态。
-
MVCC(多版本并发控制):MySQL的默认隔离级别是可重复读(Repeatable Read),通过使用Undo Log来支持MVCC,每个事务都能看到一致性的数据视图。
-
读一致性:当一个事务在执行过程中,其他事务需要读取被修改的数据时,可以通过Undo Log获取到该数据的先前版本,从而保证了读操作的一致性。
-
由于Undo Log的存在,MySQL能够提供ACID特性(原子性、一致性、隔离性和持久性),确保事务的可靠性和数据的完整性。
7.2 undolog 回滚机制:
7.2.1 undlog 日志格式:
当开启一个事务时,对于插入、修改和删除操作,MySQL的Undo Log会记录相应的日志。日志格式如下:
-
. 插入操作的日志格式:
- UNDOINSERT
- 记录了插入的行的数据(包括所有列的值)和逻辑位置信息(如表和页码)。
- 这个日志信息可以用来撤销插入操作,即删除对应的行。
-
修改操作的日志格式:
- UNDOUPDATE
- 记录了修改前的行的数据和逻辑位置信息(包括表和页码)。
- 这个日志信息可以用来撤销修改操作,即恢复到修改前的数据状态。
-
. 删除操作的日志格式:
- UNDODELETE
- 记录了被删除的行的数据和逻辑位置信息。
- 这个日志信息可以用来撤销删除操作,即重新插入已删除的行。
通过记录这些操作的Undo Log,MySQL能够实现数据的回滚。当事务回滚时,MySQL会按照事务的逆序执行Undo Log中的操作,将数据恢复到事务开始之前的状态。
Undo Log的工作方式可以理解为数据库在修改数据时,不是直接修改原始数据,而是将修改操作以日志的形式记录下来。这种日志记录的方式使得数据库具备了回滚的能力。通过从Undo Log中反向执行日志操作,数据库可以撤消对数据的修改,从而实现事务的回滚。
7.2.2 一条数据多次更新 undlog 日志记录:
在一个事务中对一条数据多次更新时,Undo Log会记录每个更新操作的日志,以便回滚事务时可以逆向执行这些更新操作。具体记录方式如下:
-
首次更新操作:
- 当第一次更新数据时,MySQL会将原始数据记录到Undo Log中,包括旧值和逻辑位置信息。
- 这个Undo Log记录的类型为UNDOINSERT或UNDOUPDATE,具体取决于是首次插入还是修改操作。
-
后续更新操作:
- 如果在同一个事务中对同一条数据进行多次更新,后续的更新操作也会被记录到Undo Log中。
- 这些更新操作的Undo Log会记录修改前的旧值和逻辑位置信息。
-
. 回滚操作:
- 当事务回滚时,MySQL会根据Undo Log中的记录逆向执行相应的更新操作,将数据恢复到事务开始之前的状态。
- 这些更新操作会按照事务中最后一次到第一次的顺序逆向执行。
通过记录每次更新操作的Undo Log,MySQL可以在回滚事务时按照更新操作的逆序将数据恢复到之前的状态。每个更新操作都会生成相应的Undo Log,包含修改前的旧值和逻辑位置信息。这样,当事务回滚时,Undo Log就能根据这些记录来逆向恢复数据,实现回滚操作。
7.3 undolog 怎么区分不同的事务:
为了区分不同的事务,Undo Log在记录时通常会包含一些标识信息来标记所属的事务。这些标识信息可以用于区分Undo Log属于哪个事务。具体的区分方式如下:
-
事务ID(Transaction ID):
- 每个事务在MySQL中都会被分配一个唯一的事务ID。
- 当Undo Log记录更新操作时,通常会将所属事务的ID也记录下来。
- 这样,Undo Log中的事务ID就可以用来区分不同的事务。
-
版本号(Transaction Version):
- 在一些特定的场景下,Undo Log也可以使用版本号来区分不同的事务。
- 每个事在执行更新操作时,可能会为每个被修改的行分配一个递增的版本号。
- 当Undo Log记录时,可以记录修改前的版本号,以便在回滚时恢复到正确的版本。
通过利用事务ID或版本号等标识信息,Undo Log可以区分不同的事务。这样,在回滚或恢复数据时,数据库就能根据这些标识信息来正确地找到属于特定事务的Undo Log,进行相应的操作。需要注意的是,不同数据库系统可能对Undo Log的实现方式和区分事务的方式有所不同。上述的标识信息只是常见的一种方式,具体的实现可能会有所差异。
7.4 undolog 大小和清理规则:
Undolog文件(也称为事务日志或回滚日志)在MySQL中是有大小限制的,通常通过参数配置进行设置。具体而言,undolog文件有以下两种类型:
-
ib_logfile:
- 这是InnoDB存储引擎使用的undolog文件类型。
- 默认情况下,每个InnoDB存储引擎的数据库实例会有两个ib_logfile文件,分别命名为ib_logfile0和ib_logfile1。
- 这些文件的大小可以通过配置参数innodb_log_file_size进行设置,默认大小为48MB。
-
undo表空间:
- 这是InnoDB存储引擎使用的Undo Log的文件类型。
- 每个数据库实例可以拥有多个undo表空间文件,其数量和大小可以通过配置参数进行设置。
- 对于每个undo表空间文件,其大小可以通过配置参数innodb_undo_tablespacesize进行设置,默认大小为10MB。
关于清理undolog文件的规则,具体而言,有以下几个方面的清理机制:
-
Checkpoint:
- 在InnoDB中,有一个后台线程称为Checkpoint线程,定期将脏页(被修改的页)写入磁盘。
- Checkpoint操作会将已经提交的事务对应的undolog文件中的记录清理掉,只保留未提交的事务的undolog记录。
-
事务提交:
- 当一个事务成功提交时,其对应的undolog记录也会被清理。
- 因为已经提交的事务不再需要进行回滚,所以相应的undolog记录可以被清理以释放空间。
-
重用空间:
- 当undolog文件中的空间被清理后,这些空间可以被重用以记录新的更新操作。
- 这样可以使得undolog文件得到更好地利用,减少生成新的undolog文件的频率。
以上是一些常见的undolog文件的大小限制和清理规则。需要注意的是,具体的清理机制可能会根据数据库的配置和版本而有所不同,因此实际操作可能会有一些细微的差异。
7.5 undolog 被占用完会发生什么:
当未提交的事务数据已经将undolog占满时,将会发生以下情况:
- 无法提交新的事务:
- 如果undolog已经被占满,那么无法再为新的事务分配undolog的空间。
- 当新的事务尝试提交时,将会失败并返回错误,指示undolog已满。
- 数据库性能下降:
- 当undolog被占满后,数据库的性能可能会受到影响。
- 由于无法为新的事务分配undolog空间,系统可能会出现阻塞或延迟,导致性能下降。
为了避免undolog被占满的问题,在设计和配置数据库时,应该根据实际需求合理设置undolog文件的大小、频繁提交事务以及及时清理undolog等策略来保证事务能够正常进行而不会占满undolog空间。
7.5 开启事务后一条sql 的执行流程:
在默认的事务隔离级别下(如MySQL的可重复读或串行化隔离级别),事务开启后执行的插入、更新、删除操作在事务提交之前不会立即持久化到磁盘上。相反,它们会先被写入到内存中的缓冲池(buffer pool)中。
缓冲池充当了内存中的数据写缓冲区,用于加速数据库的读写操作。在事务处理过程中,所有的变更都会被写入到缓冲池中,并且在缓冲池得到适当管理和刷新之前,数据不会直接写入到磁盘。
只有当事务提交时,MySQL才会将事务中所做的修改持久化到磁盘上,确保事务的原子性和持久性。此时,缓冲池中的数据会被刷新到磁盘上对应的数据文件中,包括数据页和日志文件。
需要注意的是,如果在事务提交之前发生了异常或数据库崩溃,那么未提交的事务更改将会被回滚,不会被持久化到磁盘。
如果需要立即将事务中的修改持久化到磁盘,可以使用COMMIT
命令提交事务,这将会将缓冲池中的更改刷新到磁盘。此外,也可以使用FLUSH LOGS
命令强制刷新日志文件到磁盘。
7.5 buffer pool 中的定时刷盘任务 对于尚未提交事务的sql 处理:
在buffer pool中的定时刷盘任务(通常称为checkpoint)执行时,如果遇到还未提交的事务的SQL操作,它们将按照以下方式处理:
-
写入redo log:未提交的事务的修改操作会写入redo log中,以确保事务的持久性和恢复能力。Redo log是一个事务日志,会在定期checkpoint之前强制同步到磁盘,以防止数据丢失。因此,即使事务尚未提交,相关的修改操作仍会被记录在redo log中。
-
. 不会立即刷盘:在定时刷盘任务中,遇到还未提交的事务的SQL操作时,这些修改操作不会立即被刷写到磁盘。这是因为未提交的事务可能需要进行回滚或者继续提交。
-
等待事务提交:未提交的事务的修改操作会在内存中等待事务提交。只有当事务提交时,相关的修改操作才会被刷写到磁盘。
-
完整的事务日志记录:在未提交事务的情况下执行定时刷盘任务时,相关的事务日志记录会被写入到磁盘,确保数据库的一致性和完整性。这个机制可以在数据库崩溃或重启后,通过redo log进行事务恢复。
-
InnoDB使用undolog(回滚日志)来记录数据修改前的原状,这样在事务回滚时,会将undolog中的记录恢复到修改前的状态。另一方面,修改后的数据会在buffer pool(缓冲池)中,但不会立即写入磁盘。当遇到回滚操作时,InnoDB会利用undolog中的记录,恢复数据到修改前的状态,然后将修改后的数据从buffer pool中移除。
7.6 undolog,redolog ,binlog 和buffer pool 的写入顺序:
- 修改后的数据首先会进入到buffer pool;
- 如果开启了事务 将修改的数据记录到 undolog 日志进行持久化;
- 由于buffer pool 是内存,所有要将执行的sql 写入到redolog 日志中;
- 因为redolog 文件内容是会被定时清除的,所有将修改的数据记录到binlog 一份;
- 当遇到事务回滚,根据undlog 将数据恢复到数据之前的状态,同事删除buffer pool修改后的数据,
修改Redolog的状态,如果binlog 有语句记录,则改语句不会被执行; - binlog 是ROW模式,只有在事务提交时才会写入binlog,也就是说如果事务回滚,binlog中将不会有这个事务的任何信息;如果是STATEMENT或MIXED模式,记录的是SQL语句,那么每次开始一个新的事务时,会在binlog中写入一个BEGIN,事务提交就写入COMMIT,事务回滚就写入ROLLBACK。当进行数据恢复或复制时,MySQL会读取binlog中的内容,如果遇到BEGIN就开始执行,遇到COMMIT就提交,遇到ROLLBACK就回滚,不执行该事务的SQL语句;
总结
- 为了提示读写速度,mysql 提供了buffer pool 内存,对于修改和查询操作,mysql 会按页加载数据到buffer pool 内存中;
- 对于修改的数据,mysql 后端线程定时将buffer pool 的数据刷脏,持久化的磁盘中;
- 为了防止buffer pool 数据因为mysql 宕机而丢失,通过redolog 将数据进行记录并进行持久化;
- 因为redolog 日志大小是固定的,redolog 记录的日志数据会被清除,所以使用binlog 来对所有的sql 进行记录;
- 对于事务中的sql mysql 会使用undlog 进行记录,当事务需要回滚时,使用改日志通过事务id 找到记录的数据进行事务回滚;