执行一条sql语句都经历了什么?

4,053 阅读4分钟

每天都在跟 mysql 打交道,你知道执行一条简单的 select 语句,都经历了哪些过程吗?

首先,mysql 主要是由 server 层和存储层两部分构成的。server 层主要包括连接器、查询缓存,分析器、优化器、执行器。存储层主要是用来存储和查询数据的,常用的存储引擎有 InnoDB、MyISAM,MySQL 5.5.5版本后使用 InnoDB 作为默认存储引擎。

连接器

连接器主要负责将 mysql 客户端和服务端建立连接,连接成功后,会获取当前连接用户的权限。这里获取到的权限对整个连接都有效,一旦连接成功后,如果使用管理员账号对该用户更改权限,当前连接中的拥有的权限保持不变,只有等到下次重新连接才会更新权限。

查询缓存

连接成功后,即开始要正式执行 select 语句了,但是在执行查询之前,mysql 会去看下有没有该条语句的缓存内容,如果有缓存直接从缓存中读取并返回数据,不再执行后面的步骤了,结束查询操作。

如果没有缓存则继续往后执行,并将执行结果和语句保存在缓存中。

注意在 mysql8 后已经没有查询缓存这个功能了,因为这个缓存非常容易被清空掉,命中率比较低。只要对表有一个更新,这个表上的所有缓存就会被清空,因此你刚缓存下来的内容,还没来得及用就被另一个更新给清空了。

分析器

既然没有查到缓存,就需要开始执行 sql 语句了,在执行之前肯定需要先对 sql 语句进行解析。分析器主要对 sql 语句进行语法和语义分析,检查单词是否拼写错误,还有检查要查询的表或字段是否存在。

如果分析器检测出有错误就会返回类似 "You have an error in your sql" 这样的错误信息,并结束查询操作。

优化器

通过分析器之后,mysql 就算是理解了你要执行的操作了。通常对于同一个 sql 语句,mysql 内部可能存在多种执行方案,比如存在多个索引时,该选择哪个索引,多个表关联查询时,怎么确认各个表的连接顺序。

这些方案的执行结果都一样,但是执行效率不一样,所以 mysql 在执行之前需要尝试找出一个最优的方案来,这就是优化器的主要工作。但是 mysql 也会有选择错误方案的时候,这里暂不细说,留到后面再解释原因。

执行器

经过优化器选定了一个方案后,执行器就按照选定的方案执行 sql 语句。前面我们有讲过,在连接器中会读取当前用户的权限,连接器中只是获取权限而已,并没有对权限进行判断和校验。

所以在执行器中,在执行语句之前会判断权限,如果没有对应的权限则会直接返回并提示没有相关权限。

这里你可能会问,为什么不在连接器中就直接判断权限呢,这里我觉得可能是因为 mysql 要查询的表并不一定仅限于 sql 语句中字面上的那些表,有的时候可能需要经过分析器和优化器之后才能确定到底要怎么执行,所以权限校验放在执行器中是有道理的。

注意如果是在前面的查询缓存中查到缓存之后,也会在返回结果前做权限校验的。

权限校验通过之后,就继续打开表,调用存储引擎提供的接口去查询并返回结果集数据。

到这里,一条查询 sql 语句就执行结束了。讲的比较粗糙,只是一个大致的流程,其中每一步在 mysql 的底层实现都非常复杂,后面再讲一讲索引的底层实现原理。