网站首页 > 技术文章 正文
本篇文章将介绍一条SQL语句在 MySQL中是如何执行的,包括MySQL的查询、更新操作。若想要了解MySQL中SQL语句中各关键字的执行顺序,可通过跳转文末文章链接进行阅读。
从上图中可知,MySQL内部大致分为服务层和存储引擎层两部分:
- 服务层:包含连接器、查询缓存、分析器、优化器、执行器等。涵盖MySQL的大多数核心服务功能及所有的内置函数(如日期、时间、数学和加密函数等)。所有跨存储引擎的功能都将在这一层实现,比如存储过程、触发器、视图,函数等,也包括通用的binglog日志模块。
- 存储引擎层:包含数据的存储和提取。采用可以替换的插件式架构,支持InnoDB、MyISAM、Memory等多个存储引擎。现在最常用的存储引擎是InnoDB,自MySQL 5.5.5版本后,InnoDB成为了默认的存储引擎。
接下来,我们了解一下连接器、查询缓存、分析器、优化器、执行器。
所有的SQL操作都将使用连接器,主要负责用户登录数据库时,进行用户的身份认证,包括校验用户的账户、密码、权限等操作。
其中,验证用户名和密码的过程如下:
- 若密码错误,则收到"Access denied for user"的错误,然后客户端程序结束执行。
- 若账户、密码都正确,连接器会到权限表里面查出用户拥有的权限。在此之后,整个连接里面的权限判断逻辑,都将依赖于此时查询到的权限。
需要注意的是:当管理员对一个正在连接的用户的权限进行修改,并不会影响该用户的权限。只有当修改完成后,用户重新创建的连接时,才会使用新的权限。
连接建立成功后,MySQL会先查询缓存,先校验该查询SQL是否执行过,如果之前执行过的语句,那么该语句的历史查询结果以 Key-Value对的形式缓存在内存中,Key为查询语句,Value为查询结果。如果缓存中Key被命中,就会直接返回Value给客户端,如果没有命中,就会执行后续的操作。同时,当SQL执行完成后,执行结果会被存入查询缓存中。
在获取执行缓存查询结果时,同样需要校验用户的权限。
需要注意的是:在Mysql中进行查询时并不建议使用缓存,因为对于经常更新的数据来说,每次更新表其相关的全部查询缓存都会失效,因此缓存的有效时间很短,查询缓存的命中率会非常低。但对于不经常更新的数据来说,使用缓存还是可以的。在MySQL 8.0 版本中,直接将查询缓存的整块功能删掉了。
若Mysql 没有命中缓存,那么就会进入分析器,分析器将对执行的SQL进行词法分析与语法分析,主要分为如下两个步骤:
- 第一步,词法分析,一条SQL语句由多个字符串组成,词法分析将提取关键字(比如SELECT,WHERE)、表名、字段名、查询条件等。
- 第二步,语法分析,判断输入的SQL是否正确,是否符合MySQL的语法。
需要注意的是:判断查询的字段在表中是否存在,也是在分析器这里进行。
经过分析器后,MySQL得知 SQL是做什么操作的,优化器的作用就是确定它认为的最优的执行方案(有时候实际并不是最优,仅仅是它认为最优),如,当一个表存在多个索引的时,决定使用哪个索引,或者一个语句存在多表关联(JOIN)时,决定各个表的连接顺序。
需要注意的是:因为不同的执行方案的执行效率不同,所以这一步主要是对SQL进行逻辑选择优化。
MySQL 通过分析器知道了SQL要做什么,通过优化器知道了SQL该怎么做。于是进入了执行器阶段,开始执行语句,首先执行前会校验该用户有没有权限,如果没有权限,就会返回错误信息。如果有权限,就会去调用引擎的接口,返回接口执行的结果。
Mysql是如何执行查询语句的?
SQL语句大致可以分为2类,一种是查询操作,一种是更新(插入,更新,删除)操作。我们将先分析下查询语句,语句如下:
如上SQL,实现查询学号为9527的数学成绩,我们分析下这个语句的执行流程:
step1 连接器:先检查该语句是否有权限,如果没有权限,直接返回错误信息,如果有权限,在MySQL 8.0 版本以前,会先查询缓存,以这条sql语句为key在内存中查询是否有结果,如果有直接缓存,如果没有,执行下一步。
step2 分析器:通过分析器进行词法分析,提取SQL语句的关键字,比如提取上面这个语句是查询SELECT、WHERE,提取需要查询的表名为CourseInfo,提取查询所有的字段为StudentId、Score,提取查询条件为 Course= 'Math' 与 StudentId = 9527。
然后判断在 这个SQL 语句是否有语法错误,比如关键词是否正确、各字段是否在CourseInfo种存在等等,如果检查没问题就执行下一步。
step3 优化器:接下来就是优化器进行确定执行方案,上面的SQL语句,存在有两种执行方案:
- 方案一:先查询课程为数学的所有学生的成绩,然后再查询其学号为9527的成绩。
- 方案二:先查询学号为9527的所有科目的成绩,然后再查询其科目为数学的成绩。
因此,优化器需根据自己的优化算法选择自己认为执行效率最高的一个方案(优化器认为不一定是最好)。
step4 执行器:进行权限校验,如果没有权限就会返回错误信息,如果有权限就会调用数据库引擎接口,返回引擎的执行结果。
MySQL是如何执行更新语句的?
接下来我们再看一下更新语句如何执行的,SQL语句如下:
如上SQL,我们更新学号为9527的学生的数学成绩为96分。
查询语句的执行流程,更新语句也是同样会走一遍。只不过执行更新语句时,需要记录日志,于是引入了日志模块,MySQL 自带的日志模块式 binlog(归档日志),所有的存储引擎都可以使用,同时,InnoDB引擎自带redo log 日志模块,我们将以InnoDB 引擎模式下,来看更新语句的执行流程,如下:
step1 连接器:先检查该语句是否有权限,如果没有权限,直接返回错误信息。
step2 查缓存:在一个表上有更新的时候,跟这个表有关的查询缓存会失效,所以这条语句就会把表 CourseInfo 上所有缓存结果都清空。这也就是我们一般不建议使用查询缓存的原因。
step3 分析器:分析器会通过词法和语法解析知道这是一条更新语句。
step4 优化器:优化器决定要使用 Course 这个索引。
step5 执行器:执行器先查询到学号为 9527的数学成绩记录,如果有缓存,则会使用缓存的查询结果。然后拿到查询的结果,把 Score 改为 96,得到一行新的数据,再调用引擎接口写入这行新数据,InnoDB 引擎将这行新数据更新到内存中,同时将这个更新操作记录到 redo log 里面,此时 redo log 处于 prepare 状态,然后告知执行器执行完成了,随时可以提交事务。执行器收到通知后记录binlog,然后调用引擎的提交事务接口,InnoDB 引擎把刚刚写入的 redo log 改成提交 commit 状态,更新完成。
相关阅读 : SQL查询语句的执行顺序解析
- 上一篇: Mysql基础查询语句(mysql基础查询语句大全)
- 下一篇: MySQL单表查询看这一篇文章就够了
猜你喜欢
- 2024-10-27 MySQL左查询最全介绍(sql 左查询)
- 2024-10-27 mysql查询指定父级下所有子级(mysql根据子节点查父)
- 2024-10-27 MySQL数据库入门(七)多表查询及大量练习
- 2024-10-27 mysql进行数据查询(单表查询)(mysql 查询数据表)
- 2024-10-27 【执行计划】MySQL如何执行查询?(mysql执行查询语句)
- 2024-10-27 MySQL查询列必须和group by字段一致吗?
- 2024-10-27 查看MySQL所有数据库列表(mysql怎么查看数据库列表)
- 2024-10-27 「mysql」mysql调优时必须掌握的慢查询语句排查命令
- 2024-10-27 有一张1000W 数据记录的表,主键id自增,如何随机抽取10条记录?
- 2024-10-27 MySQL进阶实战7,查询的执行过程(mysql查询机制)
- 11-26Win7\8\10下一条cmd命令可查得笔记本电脑连接过的Wifi密码
- 11-26一文搞懂MySQL行锁、表锁、间隙锁详解
- 11-26电脑的wifi密码忘记了?一招教你如何找回密码,简单明了,快收藏
- 11-26代码解决忘记密码问题 教你用CMD命令查看所有连接过的WIFI密码
- 11-26CMD命令提示符能干嘛?这些功能你都知道吗?
- 11-26性能测试之慢sql分析
- 11-26论渗透信息收集的重要性
- 11-26如何查看电脑连接过的所有WiFi密码
- 最近发表
- 标签列表
-
- cmd/c (57)
- c++中::是什么意思 (57)
- sqlset (59)
- ps可以打开pdf格式吗 (58)
- phprequire_once (61)
- localstorage.removeitem (74)
- routermode (59)
- vector线程安全吗 (70)
- & (66)
- java (73)
- org.redisson (64)
- log.warn (60)
- cannotinstantiatethetype (62)
- js数组插入 (83)
- resttemplateokhttp (59)
- gormwherein (64)
- linux删除一个文件夹 (65)
- mac安装java (72)
- reader.onload (61)
- outofmemoryerror是什么意思 (64)
- flask文件上传 (63)
- eacces (67)
- 查看mysql是否启动 (70)
- java是值传递还是引用传递 (58)
- 无效的列索引 (74)