优化器试图排除数据行的原因在于它排除数据行的速度越快,那么找到与条件匹配的数据行也就越快。如果能够首先进行最严格的测试,查询就可以执行地更快。
优化器是如何工作的?到底优化器是如何进行选择的?如果每个点都展开,那都需要很长的篇幅,我再网上翻阅了一些资料,看得也是云里雾里,后面结合专栏老师的讲解再学习吧。
这里举几个优化的示例:
示例 1
假设你的查询检验了两个数据列,每个列上都有索引:
SELECT col3 FROM mytable WHERE col1 = 'value1' AND col2 = 'value2';假设 col1 上的测试匹配了 900 个数据行,col2 上的测试匹配了 300 个数据行,而同时进行的测试只得到了 30 个数据行。
先测试 col1 会有 900 个数据行,需要检查它们找到其中的 30 个与 col2 中的值匹配记录,其中就有 870 次是失败了。
先测试 col2 会有 300 个数据行,需要检查它们找到其中的 30 个与 col1 中的值匹配的记录,只有 270 次是失败的,因此需要的计算和磁盘 I/O 更少。
其结果是,优化器会先测试 col2,因为这样做开销更小。
示例 2
尽可能地让索引列在比较表达式中独立。如果你在函数调用或者更复杂的算术表达式条件中使用了某个数据列,MySQL就不会使用索引,因为它必须计算出每个数据行的表达式值。
比如,下面的 WHERE 子句显示了这种情况。它们的功能相同,但是对于优化目标来说就有很大差异了:
WHERE mycol < 4 / 2 WHERE mycol * 2 < 4对于第一行,优化器把表达式 4/2 简化为 2,接着使用 mycol 上的索引来快速地查找小于 2 的值。
对于第二个表达式,MySQL 必须检索出每个数据行的 mycol 值,乘以 2,接着把结果与 4 进行比较。在这种情况下,不会使用索引。数据列中的每个值都必须被检索到,这样才能计算出比较表达式左边的值。
优化器的内容还可以有很多,这个专栏老师说后续会还有讲。
5 执行器下面就到了最终的执行阶段,执行开始之前,会先判断是否有操作权限,若没有,会抛出相关异常。
如果有权限,就打开表继续执行。打开表的时候,执行器就会根据表的引擎定义,去使用这个引擎提供的接口。
比如我们这个例子中的表 T 中,ID 字段没有索引,那么执行器的执行流程是这样的:
1、调用 InnoDB 引擎接口取这个表的第一行,判断 ID 值是不是 10,如果不是则跳过,如果是则将这行存在结果集中;
2、调用引擎接口取下一行,重复相同的判断逻辑,直到取到这个表的最后一行。
3、执行器将上述遍历过程中所有满足条件的行组成的记录集作为结果集返回给客户端。
至此,这个语句就执行完成了。
对于有索引的表,执行的逻辑也差不多。第一次调用的是取满足条件的第一行这个接口,之后循环取满足条件的下一行这个接口,这些接口都是引擎中已经定义好的。
可以看出,是否有索引,执行效率区别还是很大的,没有索引需要取出所有数据,一个个进行比较;而有索引则是直接取满足条件的数据;
课后题目问题:
如果表 T 中没有字段 k,而你执行了这个语句 select * from T where k=1, 那肯定是会报“不存在这个列”的错误: “Unknown column ‘k’ in ‘where clause’”。你觉得这个错误是在我们上面提到的哪个阶段报出来的呢?
答案:分析器阶段。
网友回答:
《高性能mysql》里提到解析器和预处理器。
解析器处理语法和解析查询, 生成一课对应的解析树。
预处理器进一步检查解析树的合法。比如: 数据表和数据列是否存在, 别名是否有歧义等。如果通过则生成新的解析树,再提交给优化器。
文中讲解分析器阶段时提到,MySQL 从你输入的"select"这个关键字识别出来,这是一个查询语句。它也要把字符串“T”识别成“表名 T”,把字符串“ID”识别成“列 ID”。
所以应该是分析器。
我猜测应该在分析阶段,根据文章介绍分析器的作用是让mysql知道你要做什么,对语法的分析应该是第一部,语法词法分析完成后应该是解析这条sql到底要执行什么操作,插入还是更新还是建表还是查询,这时mysql应该已经知道你想操作那个表而这个表存不存在,从而才能匹配不同的优化器类