mysql优化器对sql语句的简化(条件简化、外连接消除、子查询优化)

大多数的sql语句由人工写完后都可以转换成某种比较高效的执行形式,称为查询重写。本质上就是mysql优化器觉得你写的sql语句不好,自己再重写一遍。那重写的规则是什么?

一、条件化简

1、移除不必要的括号

((a = 5 AND b = c) OR ((a > c) AND (c < 5)))

化简成: (a = 5 and b = c) OR (a > c AND c < 5)

2、常量传递

由and连接的表达式可以进行常量的传递,例如

a = 5

a = 5 AND b > a

简化成:a=5 and b>5

3、表达式计算(重点说明)

a=5+1

化简成a=6

重点说明:如果列出啊先再函数中:abs(a)>5或者-a<-8

如上面这种优化器不会尝试对这些表达式进行化简,而这些列上如果建立了索引执行计划也不会走索引。这种情况的特点就是再列上进行了运算,如果不在列上运算(a=5+1),不会影响。

4、having和where子句的合并

如果查询语句中没有出现sum、max等的聚合函数以及group by子句,优化器就会把having子句和where子句合并。

5、常量表

查询的表中⼀条记录没有,或者只有⼀条记录。

使⽤主键等值匹配或者唯⼀⼆级索引列等值匹配作为搜索条件来查询某个表。

优化器觉得这两种查询花费的时间特别少,少到可以忽略,所以也把通过这两种⽅式查询的表称之为常量表。

优化 器在分析⼀个查询语句时,先⾸先执⾏常量表查询,然后把查询中涉及到该表的条件全部替换成常数,最后再分析其余表的查询成本

SELECT * FROM table1 INNER JOIN table2     ON table1.column1 = table2.column2     WHERE table1.primary_key = 1;

优化成:

SELECT table1表记录的各个字段的常量值, table2.* FROM table1 INNER JOIN table2     ON table1表column1列的常量值 = table2.column2;

二、外连接消除

对于优化人员,我们知道:内连接的驱动表和被驱动表的位置可以相互转换,⽽左(外)连接和右(外)连接的驱动表和被驱动表是固定的。这就导致内连接优化器可以通过改变连接顺序来降低整体的查询成本,而外连接却无法优化连接顺序(驱动表不可改变)。

可能有些人不清楚内连接和外连接的区别:可以看我以前的文章详细介绍了连接的原理(待修改)-CSDN博客

外连接和内连接的本质区别就是:对于外连接的驱动表的记录来说,如果⽆法在被驱动表中找到匹配ON⼦句中的过滤条件的记录,那么该记 录仍然会被加⼊到结果集中,对应的被驱动表记录的各个字段使⽤NULL值填充;而内连接的驱动表的记录如果⽆法在被驱动表中找到匹配ON⼦句中的过滤条 件的记录,那么该记录会被舍弃

左连接

select * from lian left join score
on lian.id = score.id;

mysql优化器对sql语句的简化(条件简化、外连接消除、子查询优化)_第1张图片

左连接执行计划

可以看到驱动表是lian表,该表由八万多条数据,而驱动表每一行都需要进行匹配,所以如果两个表进行内连接score会作为驱动表,但是左外连接,lian表作为驱动表。

怎么才能将score表作为驱动表呢,或者说换一种思路,外连接在什么情况下能转换成驱动表呢?

左外连接与内连接的转化

select * from lian left join score
on lian.id = score.id where score.id is not null;

mysql优化器对sql语句的简化(条件简化、外连接消除、子查询优化)_第2张图片

可以看到他和内连接结果是相同的。

再看看执行计划

可以看到驱动表为score。

结论

以上说明外连接在where条件中规定被驱动表不为空的时候(或者规定score.id=某值)可以转换为驱动表 。

思考:

而我也问了经验颇深的开发,他说在开发环境中左外连接用到的几率是最大的,场景如:被驱动表的记录不完整,所以需要左外连接,查询出为记录为空的被驱动表,进行信息填写,所以说实际情况下,大概率不会在where条件中进行被驱动表的规定。但是对于以上的转化,优化人员也要清楚。

你可能感兴趣的:(mysql,sql,数据库)