前言
高产似母猪,废话少说,今天刚好读到一篇关于 MySQL 语句底层如何执行的文章,以下是我的理解,分享给你们。
mysql> select * from User where ID=10086;
上面是一条非常简单的 SQL 查询语句,咋一看是不是觉得很简单,但却不懂它内部的执行流程?
根据自己的理解,我画了个不那么专业的执行流程图,先给出这条 SQL 语句的执行流程,再逐步解析每个流程,执行流程图如下:
SQL语句执行流程图
你可以清晰地看到,MySQL 其实分为两层,server 层和存储引擎层。
server 层包括 连接器、查询缓存、分析器、优化器、执行器等,这一层涵盖了 MySQL 的大部分核心功能,包括你平时用到的很多函数。从图中可以看出,不同的引擎使用同一个 Server 层。
存储引擎层则是复制数据的存储和读取。由于在 MySQL 中,存储引擎是以插件形式存在的。所以它支持 InnDB、MySAM、Memory 等引擎,其中用得最多的就是 InnDB。
这条语句执行的第一步就是连接数据库,这时会调用连接器干这个事情。他负责跟客户端建立连接、获取权限、维持和管理连接。
连接命令一般是这么写的,相信不用我过多解释。
mysql -h 192.168.0.201 -P 3306 -u root -p123
输入这条命令之后最底层就是客户端与数据库之间进行经典的 TCP 握手通信,连接完成后,连接器就开始校验当前用户的身份。
长连接指的是数据库持续拥有一个连接,短连接指每次执行完很少的几次操作就断开连接。
但是有个问题,长连接临时使用的内存管理在连接对象中,如果使用长连接,内存占用太大导致 MySQL 重启,而连接本来就是一个非常复杂的操作(想想 TCP 通信),我们又不能使用短连接。那如何取舍呢?
可以考虑以下方案:
若开启了查询缓存,之前执行过的语句会以 key-value 对的形式存在。典型应用就是 redis。
连接建立完成后,接下来,select 语句就是到查询缓存中判断是否有当前语句的缓存,若有直接返回结果集。
使用了查询缓存效率会很高。但一般不建议用,为什么?
查询缓存失效的频率非常高,只要有对表的更新,这个表的所有查询缓存就失效了,你辛苦存起来的缓存,还没使用就这么一下子就没了。对于经常更新的数据库来说,查询缓存根本没必要存在。除非你的表数据是不常变动的,建议你使用查询缓存。
如果没命中缓存就要开始执行语句了,但在执行之前 MySQL 需要知道你想干嘛。因此会对语句进行分析,这时就是分析器的活了。
首先 MySQL 会做词法分析,以上述语句为例,MySQL 就会识别出 select 关键字,分析这是查询语句,再把 User 识别成 表名 User,把字符串 "ID" 识别出 "列ID"。
经过分析器知道了做什么,在开始执行前还需要经过优化器。
它的作用就是在表里面有多个索引的时候。决定使用那个索引;或者在一个语句有多表关联的时候,决定各个表的连接顺序。优化器会选择效率最高的优化方案。
翻过万水千山终于来到了执行器,在开始执行之前,执行器会判断当前用户对表 User 是否有查询的权限。如果没有就报权限异常,(那如果当前用户没有权限,但命中了查询缓存,那 MySQL 会在返回结果时做权限认证)
如果有权限,执行流程如下(以上述语句为例):
至此执行结果完成。
以上就是我对 MySQL 查询语句执行流程的理解,希望对你们有帮助。