(一)日志篇:一条sql语句是如何执行的?

2023年 12月 29日 67.6k 0

一条普通的sql语句是如何执行的?

MySQL的内部架构及作用

今天开始是我们日志篇的内容啦,在正式开盘日志之前,需要先做个前提概要,就是搞明白一件事:MySQL是如何执行一条sql语句的。而弄清楚这个问题,就需要我们先理清楚MySQL的基础架构

基本的架构如下图, 下面以执行一条普通的select语句为例,盘一下每个组件的具体作用

image.png

从整体来说,MySQL可分为Server层和引擎层

Server层包括连接器,分析器,优化器,执行器,包含了MySQL大部分的功能。例如:所有的计算(函数,日期,时间等),存储过程,视图等。

引擎层负责数据的存和取,模式是插件式(可插拔,替换),有InnoDB, MyISAM等常见引擎。其中InnoDB为MySQL5.7版本后的默认引擎。

连接器

连接器主要负责管理连接,权限验证

无论是通过命令行窗口,Navicat,还是企业项目使用MySQL,第一步肯定是要和MySQL建立TCP连接,而这些连接工具对于MySQL来说都是客户端。连接的第一件事就是要在连接器这里做身份验证,如下:

                            mysql -h$host -P$port -u$user -p$pwd

如果密码错误,将会被拒绝连接;如果密码正确,连接器将会判断并保存登录的用户拥有的权限,之后执行任何操作(DML,DDL等)都会根据最初登录所获得的权限来做校验

登录成功后,通过 show processlist; 可看到当前客户端的连接数量

image.png

我在本地开启了两个客户端,如果连接建立后没做什么操作的话,连接就会变成Sleep(空闲)。如果太长时间没有动静的话,连接器就会主动将客户端关闭,由如下参数控制(默认是8小时):

image.png

查询缓存

缓存的作用是提升查询效率

当一条select语句进来时,会先去判断下是否有相关缓存,如果有的话,直接返回;没有的话才会去走分析器那一步。

但本质上这个功能很鸡肋,在MySQL5.7及之后的版本就已经被移除了,原因如下:

  • 如果碰到update语句,需要不断更新缓存值,在读少写多的情况下效率更差
  • 缓存是以K-V形式存储,key是查询的sql,而value是值。 只要select后面的字段随便变一下,缓存就无法命中
  • 因此在大多数情况下,MySQL的缓存功能是弊大于利的, 因此后面也被移除掉了

    分析器

    分析器的主要作用:语义,语法分析

    这时候才要开始真正执行的sql了,先交给分析器处理,让MySQL知道你想要做什么? 因此需要对sql进行预处理。比方说:

  • 如果是select *,解析具体要查询的列,将 *替换成具体的列ID;
  • 识别这条sql需要访问的表,是否规范,存在等;
  • 判断筛选的条件的列是否存在,符合规范(若有)等;
  • 以及看这条sql是否符合MySQL的语法规范,有没有乱写。如下的例子:

    image.png

    前两条sql都是被分析器检测出查询的表、筛选的字段不存在被拦截

    后一条sql则是不符合MySQL的语法规范,提示大家初学必会出现的经典的You hava an error ...

    优化器

    优化器的主要作用:生成这条sql具体的执行计划,优化方案

    讲过了分析器,那MySQL就明白你要做什么了,下一步就要开始制定执行计划。就类似做产品一样,一开始总是要知道做它的目的(为什么要做),紧接着针对这个产品开始制定一系列的方针和计划。而sql就是我们的“产品”。

    比方说,索引的选择,当关联的表比较多(需要决定表的连接顺序),以及表中的索引较多(确定走不走索引,走哪个索引合适?),选择比较多时,就需要优化器来做判断,而优化器所制定的“执行计划”,可以通过explain来查看,详细的explain分析可以参考(一)索引篇:详解MySQL索引的数据结构和类型

  • 当有join时,优化器会自动判断小表,让小表作为驱动表,详细的分析过程可以参考我这篇博客里的:当索引碰到join时的分析。(二)索引篇:详解MySQL索引失效、索引实战及慢查询分析

  • 当碰到多索引时,选哪个索引,以及走不走索引也是由优化器决定的。(后续会出相关的分析帖子哈哈!!)

  • 优化器处理完后,sql具体的执行方案就定下来了,进入下一阶段!

    执行器

    执行器的主要作用:去操作引擎拿数据,并带回数据

    当优化器告诉了MySQL要做什么,分析器告诉了要怎么去做,这时候就需要有一个执行者来行动了。

    这时候,执行器的操作顺序大致如下:

  • 打开要操作的表,去根据这个表用到的是哪个引擎,去调引擎提供的相应接口
  • 根据执行计划,没有索引的话,就调接口一行数据一行数据取,然后再判断是否符合条件
  • 如果有索引的话,就通过查字典的方式精准定位,将结果放入结果集
  • 最后,将符合条件的结果集再打包处理,返回给客户端,这条sql就处理完成了!

    日志在MySQL中起到什么作用?

    对于查询操作来说,查询总是幂等的(如果没有增删改操作,执行多少次查询结果都是一样的)。因此,我们也不必去考虑查询时,碰到的各种突发情况(断电,宕机,并发等等),会影响到数据的一致性。对于增,删,改操作就不一样了!

    执行增删改的sql,肯定也是要走 连接器->分析器->优化器->执行器 的流程。除此之外,还需要做一些安全性措施(防止出现什么意外情况,数据不会丢失,错乱)。这时候,我们的日志就要登场啦!执行一条增删改语句时,还会同时写几个日志!(MySQL三大日志,binlog;redo log;undo log悉数登场)

    binlog是干什么用的?

    binlog的主要作用是:主从复制,归档备份。

    写的时机:当MySQL执行完一条增删改sql后,执行器会将该sql写到binlog中。

    使用MySQL肯定不会对主从复制感到陌生。而从库的数据从哪里来呢?

    当主库执行增删改语句时,会将语句“写”在binlog日志里面,然后将binlog同步到从库上,从库直接执行就完事了!

    undo log是干什么用的?

    undo log的主要作用体现在两个地方,1:MVCC;2:事务的原子性

    写的时机:当MySQL执行完一条增删改sql时,执行器会调用innoDB引擎的接口将sql的反义写到undo log中。(一条insert对应delete;一条delete对应insert;一条update new 对应update old;便于回滚)

  • MySQL的快照读是通过MVCC来解决事务的并发问题的,那历史版本记录放在哪里呢?就放在undo log里面

  • 事务的原子性保证一个事务内的所有操作要么都成功,要么都失败。如果成功一半,失败了,就要通过undo log日志来回滚

  • 事务和MVCC的具体分析可以参考这篇博客详解MySQL的事务和MVCC工作机制

    redo log是干什么用的?

    redo log的主要作用:保证数据不丢失,具备crash-safe能力(InnoDB引擎独有)

    写的时机:当MySQL执行完一条增删改sql时,**执行器会调用innoDB引擎的接口将sql写到redo log中。

    如果因为突发情况而导致丢数据,那这是很危险的事情了。redo log的存在即保证了数据的不丢失,具体的原理我们会在稍后展开。

    如果将redo log, undo log, binlog都结合到MySQL的架构,则执行一条增删改语句时,执行流程如下图:

    image.png

    未完待续~~~ 后面会详细剖析每种日志的作用!

    相关文章

    Oracle如何使用授予和撤销权限的语法和示例
    Awesome Project: 探索 MatrixOrigin 云原生分布式数据库
    下载丨66页PDF,云和恩墨技术通讯(2024年7月刊)
    社区版oceanbase安装
    Oracle 导出CSV工具-sqluldr2
    ETL数据集成丨快速将MySQL数据迁移至Doris数据库

    发布评论