MySQL连接

1
2
mysql -h$ip -u$user -p

连接器

基于TCP三次握手连接

验证用户名和密码

读取权限,后面的权限逻辑判断都基于此时读到的权限

查询缓存

首先查询缓存是针对于select语句的,当表中的数据进行更新,那么此表的查询缓存就会被清空,如果刚缓存了一个查询很大的数据,还没被使用,刚好这个表有更新操作,查询缓存就被清空了

mysql8.0没有查询缓存这一步操作

解析SQL

解析器

词法分析

目的就是构建语法树

它会根据你输入的字符串识别出关键词,如SQL语句类型、表名、字段名、where后面的条件等

语法分析

检查语法

根据前面语法分析的结果,判断SQL语句是否满足MySQL语法,比如from写成form就会报错

注意这里不会验证表名和字段是否存在,解析器不做这个处理,虽然《MySQL45讲》中说是解析器做的,但是从MySQL5.7和8.0版本的源码并没有检查表和字段是否存在

执行SQL

三个阶段:

prepare阶段,预处理阶段

optimize阶段,优化阶段

execute阶段,执行阶段

预处理器

检查SQL查询语句表中的表或者字段是否存在

将select * 中的 * 扩展为所有的列

优化器

优化器主要负责将SQL查询语句的执行方案确定下来,比如表里面存在多个索引的时候,优化器会基于查询成本的考虑,来决定使用哪个索引

如下肯定是使用二级索引(name),也就是覆盖索引

1
2
// 主键索引,普通索引
select id from product where id > 1 and name like 'i%';

执行器

开始执行MySQL语句,与存储引擎进行交互,交互是以记录为单位的

存储引擎接口中通过一个while循环查询所有的记录

分三种方式:

主键索引查询

全表扫描

索引下推

主键索引扫描
1
select * from where id = 1;

优化器选择的访问类型是const,调用InnoDB引擎索引查询的接口,把id=1交给存储引擎,让存储引擎定位符合条件的的第一条记录;如果记录是不存在的,就会向执行器上报记录找不到的错误,然后查询结束,如果记录时存在的,就会将记录返回给执行器。

执行器判断是否符合查询条件,如果符合则发送给客户端,否则跳过此记录

全表扫描
1
select * from product where name = 'iphone';

优化器访问类型时all,调用InnoDB引擎全扫描的接口,把相关条件交给存储引擎,让存储引擎读取表中的满足条件的第一行记录;如果记录是不存在的,就会向执行器上报记录找不到的错误,然后查询结束,如果记录时存在的,就会将记录返回给执行器。接着再一行一行返回给客户端。

之所以客户端返回的是所有记录,是因为客户端需要等查询语句查询完成后,才会显示所有记录。

索引下推
1
select * from t_user where age > 20 and reward = 10000;

t_user表中的age和reward是联合索引

上面的sql语句只有age字段能用到联合索引,reward字段无法利用索引;是因为联合索引遇到范围查询就会停止匹配

索引下推可以减少回表次数

如果不使用索引下推,执行器与存储引擎的执行流程:

Server层首先调用存储引擎的接口定位到满足查询条件的第一条二级索引记录,获取到主键值,然后进行回表操作,将完整的记录返回到Server层,Server层的处理器再去判断是否符合条件(reward=10000),符合就返回给客户端,否则跳过,然后如此往复,查询所有满足条件的记录

如果使用索引下推,执行器与存储引擎的执行流程:

Server层首先调用存储引擎的接口定位到满足查询条件的第一条二级索引记录,然后直接判断该索引包含的列(reward列)条件是否满足(10000),如果条件不成立,则直接跳过该二级索引,否则执行回表操作,将完成记录返回给Server层;Server层在判断其他条件是否成立(本次查询没有其他条件),成立就发给客户端,否则就跳过此纪录。如此反复,查询出所有的符合条件的记录。

可以从执行计划中看到Extra部分显示了“Using index condition”,说明使用了索引下推

索引下推就是在联合索引下将条件判断放在存储引擎处理,再进行回表操作。

最左匹配原则

联合索引按照最左优先的方式进行索引匹配