一条SQL语句在MySQL中是如何执行的

目录
  • 一、mysql架构分析
    • 1.1 连接器
    • 1.2 查询缓存
    • 1.3 分析器
    • 1.4 优化器
    • 1.5 执行器
  • 二、语句分析
    • 2.1 查询语句
    • 2.2 更新语句
  • 三、总结

一、mysql架构分析

下面是mysql的一个简要架构图:

mysql主要分为Server层和存储引擎层

Server层:主要包括连接器、查询缓存、分析器、优化器、执行器等,所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图,函数等,还有一个通用的日志模块 binglog日志模块。

存储引擎: 主要负责数据的存储和读取,采用可以替换的插件式架构,支持InnoDBMyISAMMemory等多个存储引擎,其中InnoDB引擎有自有的日志模块redolog 模块。

InnoDB 5.5.5版本作为默认引擎。

1.1 连接器

主要负责用户登录数据库,进行用户的身份认证,包括校验账户密码,权限等操作,如果用户账户密码已通过,连接器会到权限表中查询该用户的所有权限,之后在这个连接里的权限逻辑判断都是会依赖此时读取到的权限数据,也就是说,后续只要这个连接不断开,即时管理员修改了该用户的权限,该用户也是不受影响的。

1.2 查询缓存

连接建立后,执行查询语句的时候,会先查询缓存,Mysql会先校验这个sql是否执行过,以Key-Value的形式缓存在内存中,Key是查询预计,Value是结果集。如果缓存key被命中,就会直接返回给客户端,如果没有命中,就会执行后续的操作,完成后也会把结果缓存起来,方便下一次调用。当然在真正执行缓存查询的时候还是会校验用户的权限,是否有该表的查询条件。

Mysql 查询不建议使用缓存,因为对于经常更新的数据来说,缓存的有效时间太短了,往往带来的效果并不好,对于不经常更新的数据来说,使用缓存还是可以的,Mysql 8.0 版本后删除了缓存的功能,官方也是认为该功能在实际的应用场景比较少,所以干脆直接删掉了。

1.3 分析器

mysql 没有命中缓存,那么就会进入分析器,分析器主要是用来分析SQL语句是来干嘛的,分析器也会分为几步:

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

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

完成这2步之后,mysql就准备开始执行了,但是如何执行,怎么执行是最好的结果呢?这个时候就需要优化器上场了。

1.4 优化器

优化器的作用就是它认为的最优的执行方案去执行(虽然有时候也不是最优),比如多个索引的时候该如何选择索引,多表查询的时候如何选择关联顺序等。

1.5 执行器

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

二、语句分析

2.1 查询语句

说了以上这么多,那么究竟一条sql语句是如何执行的呢?其实我们的sql可以分为2中,一种是查询,一种是更新(增加,更新,删除)。我们先分析下查询语句,语句如下:

select * from tb_student  A where A.age='18' and A.name='张三';

结合上面的说明,我们分析下这个语句的执行流程:

  • 先检查该语句是否有权限,如果没有权限,直接返回错误信息,如果有权限,在mysql8.0版本以前,会先查询缓存,以这条sql语句为key在内存中查询是否有结果,如果有直接缓存,如果没有,执行下一步。
  • 通过分析器进行词法分析,提取sql语句的关键元素,比如提取上面这个语句是查询select,提取需要查询的表名为tb_student,需要查询所有的列,查询条件是这个表的id='1'。然后判断这个sql语句是否有语法错误,比如关键词是否正确等等,如果检查没问题就执行下一步。
  • 接下来就是优化器进行确定执行方案,上面的sql语句,可以有两种执行方案:(1).先查询学生表中姓名为“张三”的学生,然后判断是否年龄是18。(2).先找出学生中年龄18岁的学生,然后再查询姓名为“张三”的学生。
  • 那么优化器根据自己的优化算法进行选择执行效率最好的一个方案(优化器认为,有时候不一定最好)。那么确认了执行计划后就准备开始执行了。
  • 进行权限校验,如果没有权限就会返回错误信息,如果有权限就会调用数据库引擎接口,返回引擎的执行结果。

2.2 更新语句

以上就是一条查询sql的执行流程,那么接下来我们看看一条更新语句如何执行的呢?sql语句如下:

update tb_student A set A.age='19' where A.name='张三';

我们来给张三修改下年龄,在实际数据库肯定不会设置年龄这个字段的,不然要被技术负责人打的。其实条语句也基本上会沿着上一个查询的流程走,只不过执行更新的时候肯定要记录日志啦,这就会引入日志模块了,mysql 自带的日志模块式binlog(归档日志),所有的存储引擎都可以使用,我们常用的InnoDB引擎还自带了一个日志模块redo log,我们就以InnoDB模式下来探讨这个语句的执行流程。流程如下:

  • 先查询到张三这一条数据,如果有缓存,也是会用到缓存。
  • 然后拿到查询的语句,把 age 改为19,然后调用引擎API接口,写入这一行数据,InnoDB引擎把数据保存在内存中,同时记录redo log,此时redo log进入prepare状态,然后告诉执行器,执行完成了,随时可以提交。
  • 执行器收到通知后记录binlog,然后调用引擎接口,提交redo log 为提交状态。
  • 更新完成。

这里肯定有同学会问,为什么要用两个日志模块,用一个日志模块不行吗?这就是之前mysql的模式了,MyISAM引擎是没有redo log的,那么我们知道它是不支持事务的,所以并不是说只用一个日志模块不可以,只是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, 不完整就回滚事务。

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

三、总结

  • Mysql 主要分为Server曾和引擎层,Server层主要包括连接器、查询缓存、分析器、优化器、执行器,同时还有一个日志模块(binlog),这个日志模块所有执行引擎都可以共用。
  • 引擎层是插件式的,目前主要包括,MyISAM,InnoDB,Memory等。
  • sql等执行过程分为两类,一类对于查询等过程如下:权限校验---》查询缓存---》分析器---》优化器---》权限校验---》执行器---》引擎
  • 对于更新等语句执行流程如下:分析器----》权限校验----》执行器---》引擎---redo log prepare---》binlog---》redo log commit

到此这篇关于一条SQL语句在MySQL中是如何执行的的文章就介绍到这了,更多相关SQL语句在MySQL中是如何执行的内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • PHP获取MySQL执行sql语句的查询时间方法

    如下所示: //计时开始 runtime(); //执行查询 mysql_query($sql); //计时结束. echo runtime(1); //计时函数 function runtime($mode=0) { static $t; if(!$mode) { $t = microtime(); return; } $t1 = microtime(); list($m0,$s0) = explode(" ",$t); list($m1,$s1) = explode("

  • MySQL执行update语句和原数据相同会再次执行吗

    背景 本文主要测试MySQL执行update语句时,针对与原数据(即未修改)相同的update语句会在MySQL内部重新执行吗? 测试环境 MySQL5.7.25 Centos 7.4 binlog_format为ROW 参数 root@localhost : (none) 04:53:15> show variables like 'binlog_row_image'; +------------------+-------+ | Variable_name | Value | +------

  • 详解一条sql语句在mysql中是如何执行的

    概览 最近开始在学习mysql相关知识,自己根据学到的知识点,根据自己的理解整理分享出来,本篇文章会分析下一个sql语句在mysql中的执行流程,包括sql的查询在mysql内部会怎么流转,sql语句的更新是怎么完成的. 一.mysql架构分析 下面是mysql的一个简要架构图: mysql主要分为Server层和存储引擎层 Server层:主要包括连接器.查询缓存.分析器.优化器.执行器等,所有跨存储引擎的功能都在这一层实现,比如存储过程.触发器.视图,函数等,还有一个通用的日志模块 bing

  • 一条SQL语句在MySQL中是如何执行的

    目录 一.mysql架构分析 1.1 连接器 1.2 查询缓存 1.3 分析器 1.4 优化器 1.5 执行器 二.语句分析 2.1 查询语句 2.2 更新语句 三.总结 一.mysql架构分析 下面是mysql的一个简要架构图: mysql主要分为Server层和存储引擎层 Server层:主要包括连接器.查询缓存.分析器.优化器.执行器等,所有跨存储引擎的功能都在这一层实现,比如存储过程.触发器.视图,函数等,还有一个通用的日志模块 binglog日志模块. 存储引擎: 主要负责数据的存储和

  • 一条sql语句完成MySQL去重留一

    前几天在做一个需求的时候,需要清理mysql中重复的记录,当时的想法是通过代码遍历写出来,然后觉得太复杂,心里想着应该可以通过一个sql语句来解决问题的.查了资料,请教了大佬之后得出了一个很便利的sql语句,这里分享下这段sql语句和思路. 需求分析 数据库中存在重复记录,删除保留其中一条(是否重复判断基准为多个字段) 解决方案 碰到这个需求的时候,心里大概是有思路的.最快想到的是可以通过一条sql语句来解决,无奈自己对于复杂sql语句的道行太浅,所以想找大佬帮忙. 找人帮忙 因为这个需求有点着

  • 论一条select语句在MySQL是怎样执行的

    目录 一.从宏观的角度分析MySQL 二.一条SQL执行要经过多少困难? 2-1 连接器 2-2 查询缓存 2-3 分析器 2-4 优化器 2-5 执行器 一.从宏观的角度分析MySQL 首先看一张经典图片(MySQL逻辑架构图) 上图的客户端可以直接理解为PHP.Java等.接下来,你会看到连接.线程处理.这一部分并不是MySQL所特有的,而且大多数客户端.服务器都具有类似的结构. 因此,一般而言,MySQL可以分为两层:Server层和存储引擎层. Server层主要包括连接层.查询缓存.分

  • oracle中得到一条SQL语句的执行时间的两种方式

    oracle中如果需要得到一条SQL语句的执行时间可以用如下2种方式 复制代码 代码如下: SQL> set timing on; SQL> select count(*) from wea; COUNT(*) ---------- 39490 已用时间: 00: 00: 00.06 SQL> select sql_text, elapsed_time from v$sql 2 where sql_text like 'select count(*) from wea'; 未选定行 已用

  • Spring 中jdbcTemplate 实现执行多条sql语句示例

    说一下Spring框架中使用jdbcTemplate实现多条sql语句的执行: 很多情况下我们需要处理一件事情的时候需要对多个表执行多个sql语句,比如淘宝下单时,我们确认付款时要对自己银行账户的表里减去订单所需的钱数,即需要更新银行账户的表,同时需要更新淘宝订单的表将订单状态改为"已付款",这就需要先后执行多个sql(仅仅用于表达执行多的SQL的举例说明,具体淘宝如何实现并不是很清楚~~~~~); 但如果这中间出现电脑断网断电等问题,仅将我们银行账户的钱扣掉了,订单状态并没有改,那我

  • iBatis习惯用的16条SQL语句

    iBatis 简介: iBatis 是apache 的一个开源项目,一个O/R Mapping 解决方案,iBatis 最大的特点就是小巧,上手很快.如果不需要太多复杂的功能,iBatis 是能够满足你的要求又足够灵活的最简单的解决方案,现在的iBatis 已经改名为Mybatis 了. 官网为:http://www.mybatis.org/ 1.输入参数为单个值 <delete id="com.fashionfree.stat.accesslog.deleteMemberAccessLo

  • 一条SQL语句查询多个数据库

    需求:一条SQL语句从多个数据库查询出相关联的结果,输出到客户端 调查:spring框架可以配置多数据源:sql也可以将多个数据库附加到一个主数据库下 解决办法:用ATTACH DATABASE语句将多个库添加到主库下,实现功能 语法: ATTACH DATABASE 'DatabaseName' As 'Alias-Name'; 例子: ATTACH DATABASE 'C:\Users\Administrator\Desktop\sqlite_data.sq3' As 'sd'; 总结 以上

  • 腾讯面试:一条SQL语句执行得很慢的原因有哪些?---不看后悔系列(推荐)

    说实话,这个问题可以涉及到 MySQL 的很多核心知识,可以扯出一大堆,就像要考你计算机网络的知识时,问你"输入URL回车之后,究竟发生了什么"一样,看看你能说出多少了. 之前腾讯面试的实话,也问到这个问题了,不过答的很不好,之前没去想过相关原因,导致一时之间扯不出来.所以今天,我带大家来详细扯一下有哪些原因,相信你看完之后一定会有所收获,不然你打我. 开始装逼:分类讨论 一条 SQL 语句执行的很慢,那是每次执行都很慢呢?还是大多数情况下是正常的,偶尔出现很慢呢?所以我觉得,我们还得

  • python实现一次性封装多条sql语句(begin end)

    python封装利用begin end执行多条sql 因为业务需求,优化模型运行时间.考虑到sql语句每一次执行都要建立连接,查询,获取数据耗时过多.就想到将sql一起提交上去运行,能够节省很多时间.原本1.6-2.5秒耗时的sql语句经过修改后时间降到0.3-0.6秒,感觉性能提升挺好的. 当然还有一种想法,如果有python框架的orm可能会更快,相比来说耗时基本看不到了吧,这只是我的猜想,仅仅为了优化一个模型写一个框架的话 代码可能需要改的比较多,自我感觉付出和收获不一定会成正比,当然以后

随机推荐