当前位置:Gxlcms > 数据库问题 > 高性能MySQL之基础架构

高性能MySQL之基础架构

时间:2021-07-01 10:21:17 帮助过:25人阅读

SQL_CACHE * from T where ID=10

最近我去官网看了mysql 8.0的改变,这个查询功能整块被删掉了,也就是8.0以后的版本都没有这个功能了。

 

四.分析器

如果没有命中查询缓存,就要开始真正执行语句了。首先,MySQL需要对SQL语句做解析,分析器先会 词法分析 ,mysql需要识别出你这条sql语句字符串里面的字符串分别是什么,代表什么意思。

比如,mysql会根据你输入的select这个关键字识别出来,这是一个查询语句,把“T”识别成表明T,把ID识别成 列ID。接着就是进行语法分析了,根据词法分析的结果,语法分析器会根据语法规则,判断你输入的这个SQL语句是否满足MySQL语法。如果你的语法错误,就会报出如下错误:

ERROR 1064 (42000): 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 t where ID=1 at line 1

一般语法错误会提示第一个出现错误的位置,所以关注的是紧接“use near”的内容。 

五.优化器

经过了分析器后,在执行之前,还需要经过优化器的处理,为什么还需优化器呢?因为优化器是在表里面有多个索引的时候,决定使用哪个索引;或者在一个语句有多表关联(join)的时候,决定各个表的连接顺序。比如你执行下面这样的语句,这个语句是执行两个表的join:

mysql> select * from T1 join T2 using(ID)  where T1.A=1 and T2.B=2;

这条语句既可以先从表T1里面取出A=1的记录的ID值,再根据ID值关联到表T2,再判断T2里面d的值是否等于2。也可以先从表T2里面取出B=2的记录的ID值,再根据ID值关联到T1,再判断T1里面A的值是否等于1。虽然最终执行的结果是一样的,但是执行效率却有很大的不同。再比如优化器是怎么选择索引的,例子如下:

SELECT C FROM T WHERE  A= ‘value1‘ AND B = ‘value2‘;

假设 A上的扫描了 100 个数据行,col2 上扫描 50个数据行,而同时进行的测试只得到了 50个数据行。

先根据A会有100个数据行,接着进行匹配找到其中的 30 个与 B 中的值匹配记录,其中就有 70 次是失败了。

先根据 B会有 50 个数据行,接着进行匹配找到其中的 30 个与 A中的值匹配的记录,只有 20次是失败的,很显然需要的计算和磁盘 I/O 更少。

其结果是,优化器会先选择B索引,因为这样做开销更小。而优化器的作用就是决定选择使用哪一个方案。

 

因此MySQL 的优化器主要干如下几个重要的事情:

1、选择最合适的索引;
2、选择表扫还是走索引;
3、选择表关联顺序;
4、优化 where 子句;
5、排除管理中无用表;
6、决定 order by 和 group by 是否走索引;
7、尝试使用 inner join 替换 outer join;
8、简化子查询,决定结果缓存;
9、合并试图;

六.执行器

经过优化器知道了该怎么做,于是就进入了执行器阶段,开始执行语句。开始执行的时候,要先判断一下你对这个表T有没有执行查询的权限,如果没有,就会返回没有权限的错误,如下所示。

select * from T where ID=1;

ERROR 1142 (42000): SELECT command denied to user ‘b‘@‘localhost‘ for table ‘T‘

如果有权限,就继续往下执行,这时候执行器就会根据表的引擎定义,去使用这个引擎提供的接口。

这条语句在执行器的执行流程如下:

  1. 调用InnoDB引擎接口取这个表的第一行,判断ID值是不是1,如果不是则跳过,如果是则将这行存在结果集中;

  2. 调用引擎接口取“下一行”,重复相同的判断逻辑,直到取到这个表的最后一行。

  3. 执行器将上述遍历过程中所有满足条件的行组成的记录集作为结果集返回给客户端。

至此,这个语句就执行完成了。对于有索引的表,执行的逻辑也差不多。第一次调用的是“取满足条件的第一行”这个接口,之后循环取“满足条件的下一行”这个接口,这些接口都是引擎中已经定义好的。你会在数据库的慢查询日志中看到一个rows_examined的字段,表示这个语句执行过程中扫描了多少行。这个值就是在执行器每次调用引擎获取数据行的时候累加的。

在有些场景下,执行器调用一次,在引擎内部则扫描了多行,因此引擎扫描行数跟rows_examined并不是完全相同的。我们后面会专门有一篇文章来讲存储引擎的内部机制,里面会有详细的说明。

 

三. 实战巩固

执行了这个语句 select * from T where k=1, 必然会报“不存在这个列”的错误: “Unknown column ‘k’ in ‘where clause’”。让我闷想一下这是上面哪个阶段报出来的呢?

答案:很明显是分析器阶段,因为词法分析的时候会解析出查询的表,列等等,所以此时就应该能知道表列的存在性。而且从我个人的拙见来看,如果先一步判断出这种无法查询的错误,避免后续执行,则可以避免无谓的性能开销。而表列的数据较少,完全可以这里判断。

高性能MySQL之基础架构

标签:短连接   RoCE   实战   结果   修改   ssl   val   div   isa   

人气教程排行