一条 SQL 查询语句是怎么执行的?

第 18 题

作为一名程序员,我们每天所写的程序基本都是要以数据做支撑。与数据打交道自然少不了 MySql 的身影,今天我们一起来看看当我们执行一条 SQL 语句后,MySql 究竟为我们做了什么?

我的答案

想要正确回答这道题,你需要对 Mysql 的基本架构有所了解。MySql 主要了分了 2 部分,靠近客户端的是 Server 层,数据存储是由存储引擎负责的,创建数据库时候,我们可以选择适合自己业务场景的存储引擎,例如 InnoDB,Myisam 或者 Memory。具体如下所示:

认识了 Mysql 架构的基本组成以后,我们一起来看看各个组件之间是如何串联起来为我们的 SQL 语句服务的。

连接器

主要负责处理客户端的链接,由于创建连接需要经过 TCP 握手挥手协议,同时需要进行客户端认证。因此,通常使用的过程中基本使用长连接,循环利用资源。使用了长连接以后,虽然省去了频繁创建连接的资源消耗,但是由于 SQL 执行过程中分配的临时内存是关联在连接上的,因此如果连接长时间存在,你会发现慢慢的 Mysql 占用了大量的内存。

解决方案

1. 定时释放长连接,然后重新创建。

2. Mysql 5.7 提供的 mysql_reset_connection 可以重置连接,该操作不会断开连接,只会将连接重置为初始化的状态。

查询缓存

创建连接后就是执行 SQL 语句了,执行之前 Mysql 会确认当前 SQL 是否已经执行过,执行过的结果会存储在缓存中。如果缓存命中则直接返回结果,但是面对更新比较频繁的表缓存命中率极低,因此建议设置缓存配置为 DEMAND(按需查缓存),之后我们采用如下 SQL 即可使用到缓存功能:

SELECT SQL_CACHEFROM tableA  WHERE id9 ;

需要注意的是 Mysql 8.0 开始这个功能已经被移除掉。

分析器

经过查询缓存以后就到分析阶段,该阶段分析器会对你的 SQL 语句进行词法分析。确认 SQL 的类型,例如是查询,更新还是删除?同时确认你即将要操作的表是哪个,以及操作的条件是什么。如果分析后发现 SQL 存在语法错误,或者表不存在,字段不存在都会直接报错。

例如执行 elect * from student那么你会收到如下错误:

You have an error in your SQL syntax;  check the  manual that corresponds  to your MySQL  server version for the  right syntax  to use near  ‘elect * from student’ at line  1

优化器

分析完成后就是优化了,该阶段优化器会对 SQL 进行优化。如果表中创建了索引,那么优化器会决定是否使用索引。或者如果存在表间连接查询,例如如下语句:

SELECTFROM tableA  JOIN tableB  ON tableA.id = tableB.id  WHERE tableA.a1 =  2 AND tableB.b1 =  3

对于这条语句 Mysql 有 2 种方式获取最终的结果:

1. 先按条件获取 B 表数据,然后根据 on 条件获取 A 表数据,最后得到符合 where 条件的 A 表数据。

2. 这种方式恰恰和第一种方式相反,先拿 A 表数据,再拿 B 表数据。

虽然以上都可以达到最后的效果,但是 2 种方式的性能就不同了,优化器会选择自己认为性能比较高的一种方式。

执行器

优化结束以后就是执行 SQL 语句了,Mysql 会调用存储引擎提供的接口按需获取自己需要的数据返回到客户端。执行之前还需要校验当前用户是否具有操作该表的权限,如果没有权限则拒绝执行。

总结

如上即为一条查询 SQL 的执行过程,首先客户端通过连接器连接到 Mysql 服务器端,然后进行 SQL 语句的词法信息,在经过优化器优化 SQL,最后交给执行器与存储引擎交互获取客户端请求的数据。