MySQL面试系列:SQL语句在MySQL内部的执行流程是什么?(二)

一、SQL查询语句是如何执行的?

平时在工作中,都是用框架去执行一条SQL语句,那有没有想过一条SQL在MySQL内部到底经历了哪些流程呢?

首先我们来看一张MySQL的基本架构示意图:MySQL架构示意图
从这张图中可以清楚地看到 SQL 语句在 MySQL的各个功能模块中的执行过程。

缓存模块在MySQL8.0废除

Server 层包括连接器、查询缓存、分析器、优化器、执行器等,涵盖 MySQL 的大多数核心服务功能,以及所有的内置函数(如日期、时间、数学和加密函数等),所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图等。

而存储引擎层负责数据的存储和提取。其架构模式是插件式的,支持 InnoDB、MyISAM、Memory 等多个存储引擎。
现在最常用的存储引擎是 InnoDB,它从 MySQL5.5.5 版本开始成为了默认存储引擎。

其中的细节暂时不用深究,简单了解一下即可,因为面试官一般不会问这些知识点,鸟瞰其全貌,这样能够帮助你从高维度理解问题。

二、SQL更新语句是如何执行的?

先创建一张表:

mysql> create table T(ID int primary key, c int); //表的创建语句

接下来从一个表的一条更新语句看看整个流程是怎么样的:

mysql> update T set c=c+1 where ID=2;  //执行一条update语句

(先更新数据还是先写日志?)
update语句执行流程

更新流程涉及两个重要的日志模块:redo log(重做日志)和 binlog(归档日志)

对数据文件的物理更改,保证总是先写日志,再更新数据,也就是所谓的WAL,即在持久化数据文件前,保证之前的redo log已经写到磁盘。
WAL即Write-Ahead Logging,在对数据页进行修改时, 通过将"修改了什么"这个操作记录在日志中, 而不必马上将更改内容刷新到磁盘上, 从而将随机写转换为顺序写,,提高了性能。【脏页的概念

扫描二维码关注公众号,回复: 11131539 查看本文章

redo log(重做日志)

my.cnf 配置文件中:

innodb_log_file_size = 256M
#InnoDB redo log文件大小,对应于磁盘上ib_logfile*文件。

去到MySQL的data目录下,我们可以看到ib_logfile文件。
ib_logfile文件
Redo log 以顺序的方式写入文件文件,写满时则回溯到第一个文件,进行覆盖写。
顺序写ib_logfile

redo log包括两部分:一是内存中的日志缓冲(redo log buffer),该部分日志是易失性的;二是磁盘上的重做日志文件(redo log file),该部分日志是持久的。

Redo 写盘操作

参数innodb_flush_log_at_trx_commit 作用于事务提交时,写入磁盘策略

  • 当设置该值为1时,每次事务提交都要做一次fsync,这是最安全的配置,即使宕机也不会丢失事务;
  • 当设置为2时,则在事务提交时只做write操作,只保证写到系统的page cache,因此实例crash不会丢失事务,但宕机则可能丢失事务;
  • 当设置为0时,事务提交不会触发redo写操作,而是留给后台线程每秒一次的刷盘操作,因此实例crash将最多丢失1秒钟内的事务。
    写入磁盘策略

还有其他场景也可能会触发redo log写文件(简单了解,这里又能引出很多知识点):

  • Redo log buffer空间不足时
  • 后台线程
  • 做checkpoint
  • 实例shutdown时
  • binlog切换时

有了 redo log,InnoDB 就可以保证即使数据库发生异常重启,之前提交的记录都不会丢失,这个能力称为crash-safe。

binlog(归档日志)

redo log是 InnoDB 引擎特有的日志,而 binlog是Server 层的日志,所有引擎都可以使用。

my.cnf 配置文件中:

log_bin =/usr/local/mysql/data #二进制日志存放路径
binlog_format = row
#binlog格式,复制有3种模式STATEMENT,ROW,MIXED
sync_binlog = 1
#sync_binlog=0(默认),事务提交后MySQL不刷新binlog_cache到磁盘,而让Filesystem自行决定,或者cache满了才同步。
#sync_binlog=n,每进行n次事务提交之后,MySQL将binlog_cache中的数据强制写入磁盘。

磁盘上存储的binlog日志文件:
binlog日志

innodb_flush_log_at_trx_commit =1 和 sync_binlog = 1 双11配置,保证数据库的安全性。

MySQL为什么会有两份日志呢?

因为最开始 MySQL 里并没有 InnoDB 引擎。MySQL 自带的引擎是 MyISAM,但是MyISAM 没有 crash-safe 的能力,binlog 日志只能用于归档。而 InnoDB 是另一个公司以插件形式引入 MySQL 的,既然只依靠 binlog 是没有 crash-safe 能力的,所以InnoDB 使用另外一套日志系统——也就是 redo log 来实现 crash-safe 能力。
因为要写两份日志文件,那必然会存在redo log与binlog的一致性问题;MySQL通过内部XA机制解决这种一致性的问题。将 redo log 的写入拆成了两个步骤:prepare 和 commit,这就是"两阶段提交"。【XA分布式事务

这里就简单的看看XA的概念:
XA(分布式事务)规范主要定义了(全局)事务管理器(TM: Transaction Manager)和(局部)资源管理器(RM: Resource Manager)之间的接口。XA为了实现分布式事务,将事务的提交分成了两个阶段:也就是2PC (tow phase commit),XA协议就是通过将事务的提交分为两个阶段来实现分布式事务。
看完概念,在通过上面的流程图,应该有个大概的了解2PC的是什么了。

两阶段提交
第一阶段:InnoDB prepare, write/sync redo log;binlog不作任何操作;
第二阶段:包含两步,write/sync Binlog; InnoDB commit (commit in memory)

当第二阶段的第1步执行完成之后,binlog已经写入,MySQL会认为事务已经提交并持久化了(在这一步binlog就已经ready并且可以发送给订阅者了)。
第二阶段的第2步大部分都是内存操作,比如释放锁,释放MVCC相关的read view等等。
(思考:为什么必须有“两阶段提交”呢?)

undo log(撤消日志)

在数据修改的时候,不仅记录了redo log,同时也记录了undo log。(其他文章介绍了系统表空间(ibdata)、独立的Undo 表空间,其实对于面试来说暂时不用深度研究)

核心点
undo log的作用:事务回滚多版本控制(MVCC)崩溃恢复

下一章来说说undo log的作用

小结

从一个简单的SQL语句,我们仅仅把相关日志部分学习了一下,如果还对每个环节的展开细节存有疑问或者某个地方写的不对,欢迎留言评论和指正。

发布了3 篇原创文章 · 获赞 5 · 访问量 738

猜你喜欢

转载自blog.csdn.net/Oooo_mumuxi/article/details/105750622