其乐融融的IT技术小站

面试被问到MySQL中一条SQL语句的执行过程

MySQL作为最常用的关系型数据库,无论是在应用还是在面试中都是必须掌握的技能。

要印在脑子里面的东西

  • DDL:数据定义,它用来定义数据库对象,包括库,表,列,通过ddl我们可以创建,删除,修改数据库和表结构;
  • DML:数据操作语言,增加删除修改数据表中的记录;
  • DCL:数据控制语言,定义访问权限和安全级别;
  • DQL:数据查询语言,用它来查询想要的记录。

SQL执行顺序:

  • from;
  • join
  • on
  • where;
  • group by;
  • avg,sum.... 使用聚集函数进行计算;
  • having;
  • select;
  • distinct;
  • order by;
  • limit;

接下来我们就来鸟瞰msyql查询的全貌,以下面这条sql为例。

select * from T where ID=1000;

引用极客时间的这张生动的图:

MySQL分为server层和存储引擎层

1.Server层

server层实际上就是对sql语句进行检查,分析,优化,执行,完成这些就必须拥有一些工具:连接器,查询缓存,分析器,优化器,执行器。

server层还包括我们使用的所有内置函数,比如日期相关函数,时间相关函数,数学相关函数,加密相关函数等等。

server层还包含跨存储引擎的功能,包括存储过程,触发器,视图。

总之除了存储,其他功能都是server层干的。

(1) 连接器

连接器负责跟客户端建立连接、获取权限、维持和管理连接,当一个连接请求过来后,首先迎接的就是连接器,连接器除了校验密码外还要去获取当前账号所拥有的权限并保存起来,供后续流程使用,这样一来,只要链接不断开,就算你修改了密码也不会影响到当前已经建立的连接。

连接又分为长连接和短连接,长连接一般会一直维持,如果长时间不操作,mysql就会判断静止时间是否超过参数wait_timeout配置的时间,如果超过就主动断开,这个参数默认是8小时;短连接是指每次执行完很少的几次查询后就断开,下次查询就会再重新建立链接。

对于到底要使长连接还是短连接也是一个值得思考的问题,长连接可以避免频繁创建连接带来的性能消耗,因为毕竟建立连接过程还是比较复杂的,但是长连接中,随着执行sql的数量,可能会导致缓存增多,这些缓存只能等到连接关闭才能释放,所以如果长连接很多,也会有内存被占用过多的风险,从而导致OOM,进而导致进程被系统杀死。

那么短连接的好处和坏处就不言而喻了。

如果你用的是MySQL 5.7或更新版本,可以在每次执行一个比较大的操作后,通过执行mysql_reset_connection来重新初始化连接资源。这个过程不需要重连和重新做权限验证,但是会将连接恢复到刚刚创建完时的状态。

(2) 查询缓存

mysq建立连接后,mysql会先查询缓存,如果开启缓存,mysql就会把查过的sql以key-value对的形式缓存起来,sql语句是key,查询结果是value。

mysql的缓存其实并不友好,对于一个变化比较频繁的表,前一秒查询该表,并把结果缓存起来,后一秒对该表做了更新操作,那么缓存就会被清空,就造成辛辛苦苦保存的缓存还没使用就被清空了,这样给整个工作没有带来效率反而带来消耗。

因此只有静态表才适合使用缓存,静态表一般不怎么变化,但是查询又比较频繁,比如配置表。

但是一般配置表本身就不会太大,不用缓存也不会看出有明显效率问题,这也许就是MySQL 8.0版本直接将查询缓存的整块功能删掉的原因吧。

(3) 分析器

如果没有命中缓存,那就需要去执行sql语句了,我们写了一条查询语句,看起来实际就是一串字符串,那mysql怎么知道这一串字符串是符合要求且能执行的sql语句呢?分析器就是负责做这件事。

分析器先会做“词法分析”。你输入的是由多个字符串和空格组成的一条SQL语句,MySQL需要识别出里面的字符串分别是什么,代表什么。 MySQL从你输入的"select"这个关键字识别出来,这是一个查询语句。它也要把字符串“T”识别成“表名T”,把字符串“ID”识别成“列ID”。

做完了这些识别以后,就要做“语法分析”。根据词法分析的结果,语法分析器会根据语法规则,判断你输入的这个SQL语句是否满足MySQL语法。如果你的语句不对,就会收到“You have an error in your SQL syntax”的错误提醒。

一般语法错误会提示第一个出现错误的位置,所以你要关注的是紧接“use near”的内容。

(4) 优化器

解析器已经知道这条sql语句要做什么?能不能做?接下来就是优化器来决定怎么做,一条sql语句是可以很复杂的,各种表连接和子查询等等,优化器要做的就是给这条复杂的sql寻找一个优化成查询效率相对高的策略,比如使用哪个索引,表连接的顺序等等都是在这里确认,一条sql的查询性能和优化器的处理是分不开的。

总之优化器处理完,查询方案就已经确定了。mysql的优化器里面涉及到很多的算法,算是比较复杂的一个模块,后面我们在sql优化里面单独讨论。

(5) 执行器

MySQL通过分析器知道了你要做什么,通过优化器知道了该怎么做,于是就进入了执行器阶段,开始执行语句:

  • 第一步就是校验权限,看当前用户是否对当前查询的表具有查询权限。
  • 第二步如果权限校验通过,就开始调用存储引擎的接口取出表的第一行数据,然后判断id是不是1000,如果是就存到结果集中,如果不是则跳过。
  • 第三步再调用存储引擎引擎接口取出表的第二行数据,再进行上述判断,直到查到最后一行数据。

如果表中有索引,无非是在上述流程加一些索引的逻辑,后续会详细说明,但是整体的逻辑原理是没有变的。

2.存储引擎层

存储引擎顾名思义就是和存储有关,必然要和磁盘交互,msyql的存储引擎是插件式的架构模式,这就使得mysql的存储引擎可以单独实现,也使得msyq的存储引擎可以不止一种类型,mysql常用的存储引擎是InnoDB、MyISAM、Memory,在MySQL 5.5.5版本InnoDB成为mysql的默认存储引擎。当然在创建sql语句的时候也是可以指定使用哪一种存储引擎的。

存储引擎主要是提供存取功能,主要是通过自身提供的api供server层调用,从而是实现存取功能。

为了提高效率,不同的引擎会有不同的策略,InnoDB的索引结构就是为了提高查询效率的一种数据结构。

赞 ()
分享到:更多 ()

相关推荐

内容页底部广告位3
留言与评论(共有 0 条评论)
   
验证码: