首先我们来看这样一条查询语句:
mysql> select * from T where ID=10;
这是一条我们平日开发中经常使用的查询语句,我们都知道它可以返回查询结果,却不知道他是如何执行的,所以今天我们就对mysql进行具体的拆解,来了解查询背后的来龙去脉
上面是一张MySQL的逻辑架构图,我们可以很清晰的看出,mysql主要分为两大部分,存储引擎和服务层,服务层包括查询缓存,连接器,分析器,优化器等,包含了mysql绝大多数的核心功能,以及内置函数,而存储引擎比较有代表的就是InnoDB、MyISAM,它的功能就是负责数据的存储和输出,从5.5开始,mysql默认使用了innodb引擎。
连接器
当我们使用mysql时,第一步要做的是什么呢?没错连接数据库,连接器负责的就是这部分功能,跟客户端建立连接、以及获取用户的权限等
mysql -h$ip -P$port -u$user -p
当连接成功之后,你可以在 show processlist 命令中看到它。文本中这个图是 show processlist 的结果,其中的 Command 列显示为“Sleep”的这一行,就表示现在系统里面有一个空闲连接
数据库连接分为两种,长短连接,长连接是当客户端不间断的有请求,则使用同一个连接。而短连接则是指每次执行完请求就要断开连接,下次请求再重新建立连接,显而易见的是,简历连接需要成本,建议大家在项目中尽量使用长连接
查询缓存
查询缓存在实际中很少应用,同时MySQL 8.0 版本直接将查询缓存的整块功能删掉了,在这里不多做赘述
分析器
当你的语句到达MySQL时,MySQL该如何操作呢,首先,它需要知道你是来做什么的,因此要对你发送过来的语句进行解析。分析器先会做“词法分析”。你输入的是由多个字符串和空格组成的一条 SQL 语句,MySQL 需要识别出里面的字符串分别是什么,代表什么。MySQL 从你输入的"select"这个关键字识别出来,这是一个查询语句。它也要把字符串“T”识别成“表名 T”,把字符串“ID”识别成“列 ID”。做完了这些识别以后,就要做“语法分析”。根据词法分析的结果,语法分析器会根据语法规则,判断你输入的这个 SQL 语句是否满足 MySQL 语法。
优化器
经过分析器之后,mysql已经知道了你要做什么,但条条大路通罗马,到底要走哪条路呢,这还要由优化器决定,当你的表有多个索引时,或者在进行连表查询时,优化器会判断使用哪个方案更加的快捷
mysql> select * from t1 join t2 using(ID) where t1.c=10 and t2.d=20;
既可以先从表 t1 里面取出 c=10 的记录的 ID 值,再根据 ID 值关联到表 t2,再判断 t2 里面 d 的值是否等于 20。
也可以先从表 t2 里面取出 d=20 的记录的 ID 值,再根据 ID 值关联到 t1,再判断 t1 里面 c 的值是否等于 10。
两种方案执行结果是一样的,优化器会选定效率较高的方案,至此,执行方案就确定了,至于怎样判定效率的高低,这个后面章节详细说明
执行器
当选定了执行语句之后,就要进入到执行阶段
mysql> select * from T where ID=10;
第一步,权限校验,校验是否有权执行操作
第二步,调用 引擎接口取这个表的第一行,判断 ID = 10 ?,如果不是则跳过,如果是则将这行存在结果集中
第三步,调用引擎接口取“下一行”,重复上一步,直到表的最后一行。
第四步,执行器将结果集返回给客户端
至此语句就算完成了
对于有索引的表,执行的逻辑类似。第一次调用的是“取满足条件的第一行”这个接口,之后循环取“满足条件的下一行”这个接口,这些接口都是引擎中已经定义好的。你会在数据库的慢查询日志中看到一个 rows_examined 的字段,表示这个语句执行过程中扫描了多少行。这个值就是在执行器每次调用引擎获取数据行的时候累加的。在有些场景下,执行器调用一次,在引擎内部则扫描了多行,因此引擎扫描行数跟 rows_examined 并不是完全相同的。我们后面会专门有一篇文章来讲存储引擎的内部机制,里面会有详细的说明。
今天我们一起学习了 MySQL 的逻辑架构,对一个 SQL 语句完整执行流程的各个阶段有了简单的印象。执行流程的具体细节,在后面的章节进行具体讲解