一条sql语句在MySQL的执行流程

2年前基础语言49717
一条sql语句在MySQL的执行流程 遇见8099 于2022-10-07 21:41:55发布 525 收藏 3 文章标签: mysql sql 数据库 一条sql语句在MySQL的执行流程

Server层和存储引擎层

Server层

连接器: 身份认证和权限相关(登录 MySQL 的时候)。查询缓存: 执行查询语句的时候,会先查询缓存(MySQL 8.0 版本后移除,因为这个功能不太实用)。分析器: 没有命中缓存的话,SQL 语句就会经过分析器,分析器说白了就是要先看你的 SQL 语句要干嘛,再检查你的 SQL 语句语法是否正确。优化器: 按照 MySQL 认为最优的方案去执行。执行器: 执行语句,然后从存储引擎返回数据。

分析器: 第一步,词法分析,一条 SQL 语句有多个字符串组成,首先要提取关键字,比如 select,提出查询的表,提出字段名,提出查询条件等等。做完这些操作后,就会进入第二步。

第二步,语法分析,主要就是判断你输入的 sql 是否正确,是否符合 MySQL 的语法。

优化器: 优化器的作用就是它认为的最优的执行方案去执行(有时候可能也不是最优,这篇文章涉及对这部分知识的深入讲解),比如多个索引的时候该如何选择索引,多表查询的时候如何选择关联顺序等。

可以说,经过了优化器之后可以说这个语句具体该如何执行就已经定下来。 执行器:

当选择了执行方案后,MySQL 就准备开始执行了,首先执行前会校验该用户有没有权限,如果没有权限,就会返回错误信息,如果有权限,就会去调用引擎的接口,返回接口执行的结果。

存储引擎层 主要负责数据的存储和读取,采用可以替换的插件式架构,支持 InnoDB、MyISAM、Memory 等多个存储引擎,其中 InnoDB 引擎有自有的日志模块 redolog 模块。现在最常用的存储引擎是 InnoDB,它从 MySQL 5.5.5 版本开始就被当做默认存储引擎了。

1、一条查询语句 连接器先检查权限,查询缓存,如果有缓存就直接缓存,没有缓存下一步;分析器进行词法分析,提取select 表名,条件等。然后判断语法是否有误正常就下一步优化器确定执行方案,查询可能有两种执行方案 a.先查询学生表中姓名为“张三”的学生,然后判断是否年龄是 18。 b.先找出学生中年龄 18 岁的学生,然后再查询姓名为“张三”的学生。

选择一个他认为效率最好的执行

执行器:进行权限校验,有权限就调用数据库引擎 2、一条更新语句

既然是更新,肯定要记录日志。mysql自带的binlog(归档日志),InnoDB自带的redo log(重做日志)。

update tb_student A set A.age='19' where A.name=' 张三 '; 连接器检查权限先查张三这条数据,有缓存就清除分析器分析语句 把年龄改为19,调用引擎API接口,写入这行数据;InnoDB引擎把数据保存在内存中,同时记录redo log,此时redo log进入prepare状态,然后告诉执行器,执行完成了,随时可以提交事务。执行器收到通知后记录binlog,并把binlog写入磁盘;然后调用引擎接口,redo log为提交状态更新完成

这里肯定有人会问,为什么要用两个日志模块,用一个日志模块不行吗?

这是因为最开始 MySQL 并没与 InnoDB 引擎( InnoDB 引擎是其他公司以插件形式插入 MySQL 的) ,MySQL 自带的引擎是 MyISAM,但是我们知道 redo log 是 InnoDB 引擎特有的,其他存储引擎都没有,这就导致会没有 crash-safe 的能力(crash-safe 的能力即使数据库发生异常重启,之前提交的记录都不会丢失),binlog 日志只能用来归档。

并不是说只用一个日志模块不可以,只是 InnoDB 引擎就是通过 redo log 来支持事务的。那么,又会有同学问,我用两个日志模块,但是不要这么复杂行不行,为什么 redo log 要引入 prepare 预提交状态?这里我们用反证法来说明下为什么要这么做?

先写 redo log 直接提交,然后写 binlog,假设写完 redo log 后,机器挂了,binlog 日志没有被写入,那么机器重启后,这台机器会通过 redo log 恢复数据,但是这个时候 bingog 并没有记录该数据,后续进行机器备份的时候,就会丢失这一条数据,同时主从同步也会丢失这一条数据。

先写 binlog,然后写 redo log,假设写完了 binlog,机器异常重启了,由于没有 redo log,本机是无法恢复这一条记录的,但是 binlog 又有记录,那么和上面同样的道理,就会产生数据不一致的情况。

如果采用 redo log 两阶段提交的方式就不一样了,写完 binglog 后,然后再提交 redo log 就会防止出现上述的问题,从而保证了数据的一致性。那么问题来了,有没有一个极端的情况呢?假设 redo log 处于预提交状态,binglog 也已经写完了,这个时候发生了异常重启会怎么样呢? 这个就要依赖于 MySQL 的处理机制了,MySQL 的处理过程如下:

判断 redo log 是否完整,如果判断是完整的,就立即提交。如果 redo log 只是预提交但不是 commit 状态,这个时候就会去判断 binlog 是否完整,如果完整就提交 redo log, 不完整就回滚事务。

这样就解决了数据一致性的问题。

相关文章

Python正则表达式详解

Python正则表达式详解...

猿创征文|弃文从工,从小白到蚂蚁工程师,我的 Java 成长之路

猿创征文|弃文从工,从小白到蚂蚁工程师,我的 Java 成长之路...

顺序表的基本操作(超详细)

顺序表的基本操作(超详细)...

想换壁纸找不到高质量的?来这里用python采集上万张壁纸

想换壁纸找不到高质量的?来这里用python采集上万张壁纸...

太厉害了,终于有人能把文件上传漏洞讲的明明白白了

太厉害了,终于有人能把文件上传漏洞讲的明明白白了...

详细sqli-labs(1-65)通关讲解

详细sqli-labs(1-65)通关讲解...