MySQL优化器的SQL重写规则介绍

 更新时间:2024年07月12日 10:50:51   作者:让你三行代码QAQ  
这篇文章主要介绍了MySQL优化器的SQL重写规则,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

MySQL优化器的SQL重写规则

MySQL优化器会根据一定的规则对输入的SQL在保证含义不变的情况下进行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.常量传递

例如:

a = 5 AND b >a;
--优化后
a = 5 AND b >5;  

3.等值传递

例如:

a = b and b = c and c = 5;
--优化后
a = 5 and b = 5 and c = 5;

4.移除没用的条件

例如:

a < 1 and b= b;
-- 优化后
a < 1;

5.表达式计算

例如:

a = 1 + 1;
--优化后
a = 2;

但是对于复杂的无法优化,例如:

-a < -8;
max(a) > 8;

6.常量表检测

在使用主键索引或则唯一性的二级索引进行等值匹配时候,MySql认为查询耗时很少,可以忽略。因此MySQL将这种条件的查询作为一个常量表来处理。

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

例如:

select *
from table1 a
         left join table2 b
                   on a.id = b.id
where
  and a.id = 1;

这个查询可以使用主键和常量值的等值匹配来查询table1表,也就是在这个查询中table1表相当于常量表,在分析对table2表的查询成本之前,就会执行对table1表的查询,并把查询中涉及table1表的条件都替换掉:

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

7.外连接消除

内连接的驱动表和被驱动表的位置可以相互转换,而外连接的驱动表和被驱动表是固定的。

这就导致内连接可能通过优化表的连接顺序来降低整体的查询成本,而外连接却无法优化表的连接顺序。

如果外连接查询的列行数和内连接查询的行数相同,即查询内容相同,也就是说外连接中驱动表没有多余的列,那么MySQL就会将外连接转换为内连接来执行SQL,这就是外连接消除。

8.子查询优化

8.1子查询类型

按返回的结果集区分子查询,子查询分为以下几种:

  • 标量子查询:那些只返回一个单一值的子查询称之为标量子查询。
  • 行子查询:就是返回一条记录的子查询,不过这条记录需要包含多个列(只包含一个列就成了标量子查询了)。
  • 列子查询:列子查询自然就是查询出一个列的数据,不过这个列的数据需要包含多条记录(只包含一条记录就成了标量子查询了)。
  • 表子查询:就是子查询的结果既包含很多条记录,又包含很多个列。

按与外层查询关系来区分子查询,可分为:

  • 不相关子查询:如果子查询可以单独运行出结果,而不依赖于外层查询的值,我们就可以把这个子查询称之为不相关子查询。
  • 相关子查询:如果子查询的执行需要依赖于外层查询的值,我们就可以把这个子查询称之为相关子查询,比如:SELECT * FROM e1 WHERE m1 IN (SELECT m2 FROM e2 WHERE n1 = n2);

[NOT] IN/ANY/SOME/ALL子查询

对于列子查询和表子查询来说,它们的结果集中包含很多条记录,这些记录相当于是一个集合,所以就不能单纯的和另外一个操作数使用操作符来组成布尔表达式了,MySQL通过下面的语法来支持某个操作数和一个集合组成一个布尔表达式。

  • IN或者NOT IN:例如:SELECT * FROM e1 WHERE (m1, n1) IN (SELECT m2, n2 FROM e2);
  • ANY/SOME:例如:SELECT * FROM e1 WHERE m1 > ANY(SELECT m2 FROM e2);等价于SELECT * FROM e1 WHERE m1 > (SELECT MIN(m2) FROM e2);
  • ALL:例如:SELECT * FROM e1 WHERE m1 > ALL(SELECT m2 FROM e2);等价于SELECT * FROM e1 WHERE m1 > (SELECT MAX(m2) FROM e2);
  • EXISTS子查询:例如SELECT * FROM e1 WHERE EXISTS (SELECT 1 FROM e2);

8.2子查询优化

标量子查询、行子查询的执行方式

  • 对于不相关标量子查询或者行子查询来说,先单独执行子查询,然后将子查询结果作为条件执行外出查询,也就是说,分别执行外层查询和子查询,两个单表操作。
  • 对于相关的标量子查询或者行子查询来说,先从外层查询取出一条数据,然后将某列作为条件去匹配子查询,如果成立放入结果集,如果不成立,舍弃。

物化表

  • 对于行子查询或表子查询来说,子查询返回的结果集不止一条,外层去匹配子查询结果集效率极低。那么MySQL采用临时表的解决方法,该临时表的列就是子查询结果集中的列,也就是物化表。
  • 物化表建立方式:写入临时表的记录会被去重,临时表也是个表,只要为表中记录的所有列建立主键或者唯一索引。一般情况下子查询结果集不会大的离谱,所以会为它建立基于内存的使用Memory存储引擎的临时表,而且会为该表建立哈希索引。如果子查询的结果集非常大,超过了系统变量tmp_table_size或者max_heap_table_size,临时表会转而使用基于磁盘的存储引擎来保存结果集中的记录,索引类型也对应转变为B+树索引。

物化表转连接

所谓物化表转连接,就是外层表和物化表做连接查询,MySQL通过计算外层表作为驱动表和物化表作为驱动表进行连接查询的查询成本,然后使用成本较低的方式进行查询。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • MySQL中的唯一性约束与NULL详解

    MySQL中的唯一性约束与NULL详解

    这里记录的是很久之前的一个 bug 了,主要给大家介绍了关于MySQL中唯一性约束与NULL的相关资料,文中介绍的非常详细,对大家具有一定的参考学习价值,需要的朋友们下面来一起看看吧。
    2017-05-05
  • Mysql中Binlog3种格式的介绍与分析

    Mysql中Binlog3种格式的介绍与分析

    这篇文章主要给大家介绍了关于Mysql中Binlog3种格式的介绍与分析,文中介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-10-10
  • mysql脏页是什么

    mysql脏页是什么

    本文主要介绍了什么是mysql脏页,为什么会出现脏页,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-07-07
  • Mysql 8.0安装及重置密码问题

    Mysql 8.0安装及重置密码问题

    这篇文章主要介绍了Mysql 8.0安装及重置密码问题,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-11-11
  • MySQL存储过程in、out和inout参数示例和总结

    MySQL存储过程in、out和inout参数示例和总结

    这篇文章主要给大家介绍了关于MySQL存储过程in、out和inout参数的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • MySQL中order by排序时数据存在null则排序在最前面的方法

    MySQL中order by排序时数据存在null则排序在最前面的方法

    order by排序是最常用的功能,但是排序有时会遇到数据为空null的情况,这样排序就会乱了,这篇文章主要给大家介绍了关于MySQL中order by排序时数据存在null则排序在最前面的相关资料,需要的朋友可以参考下
    2024-06-06
  • 基于一致性hash算法(consistent hashing)的使用详解

    基于一致性hash算法(consistent hashing)的使用详解

    本篇文章对一致性hash算法(consistent hashing)的使用进行了详细的分析介绍。需要的朋友参考下
    2013-05-05
  • MySQL中COALESCE函数示例详解

    MySQL中COALESCE函数示例详解

    COALESCE 是一个功能强大且常用的 SQL 函数,主要用来处理 NULL 值和实现灵活的值选择策略,能够使查询逻辑更清晰、简洁,这篇文章主要介绍了MySQL中COALESCE函数,需要的朋友可以参考下
    2025-03-03
  • mysql函数split功能实现

    mysql函数split功能实现

    mysql 5.* 的版本现在没有split 函数,但有些地方会用,在这里就简单记录一下
    2012-09-09
  • Finished with error:Navicat运行SQL文件报错的解决

    Finished with error:Navicat运行SQL文件报错的解决

    这篇文章主要介绍了Finished with error:Navicat运行SQL文件报错的问题及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-04-04

最新评论