微信号:weixin888
经过了分析器,MySQL?就知道你要做什么了。在开始执行之前,还要先经过优化器的处理。
优化器是在表里面有多个索引的时候,决定使用哪个索引;或者在一个语句有多表关联(join)的时候,决定各个表的连接
顺序。比如你执行下面这样的语句,这个语句
是执行两个表的?join:
既可以先从表?test1?里面取出?name=yangguo的记录的?ID?值,再根据?ID?值关联到表?test2,再判断?test2?里面?name的
值是否等于?yangguo。
也可以先从表?test2?里面取出?name=xiaolongnv?的记录的?ID?值,再根据?ID?值关联到?test1,再判断?test1?里面?name
的值是否等于?yangguo。
这两种执行方法的逻辑结果是一样的,但是执行的效率会有不同,而优化器的作用就是决定选择使用哪一个方案。优化器阶段
完成后,这个语句的执行方案就确定下来了,然后进入执行器阶段。如果你还有一些疑问,比如优化器是怎么选择索引的,有
没有可能选择错等等。
开始执行的时候,要先判断一下你对这个表?T?有没有执行查询的权限,如果没有,就会返回没有权限的错误,如下所示?(在
工程实现上,如果命中查询缓存,会在查询缓存返回结果的时候,做权限验证。查询也会在优化器之前调用?precheck?验证权
限)。
如果有权限,就打开表继续执行。打开表的时候,执行器就会根据表的引擎定义,去使用这个引擎提供的接口。
比如我们这个例子中的表?test?中,ID?字段没有索引,那么执行器的执行流程是这样的:
至此,这个语句就执行完成了。对于有索引的表,执行的逻辑也差不多。第一次调用的是“取满足条件的第一行”这个接
口,之后循环取“满足条件的下一行”这个接口,这些接口都是引擎中已经定义好的。你会在数据库的慢查询日志中看到一个
rows_examined?的字段,表示这个语句执行过程中扫描了多少行。这个值就是在执行器每次调用引擎获取数据行的时候累加
的。在有些场景下,执行器调用一次,在引擎内部则扫描了多行,因此引擎扫描行数跟?rows_examined?并不是完全相同的。