【MySQL】基于规则的优化(内含子查询优化;派生表;物化表;半连接;标量子查询;行子查询)

news2024/11/24 18:37:03

概念

  • 常量表:下述两种查询方式查询的表:

    • 类型1:查询的表中一条记录都没有,或者只有一条记录

    • 类型2:使用主键等值匹配或者唯一二级索引列等值匹配作为搜索条件来查询某个表

  • 派生表:放在FROM子句后面的子查询称为派生表。

  • 物化:将子查询结果集中的记录保存到临时表的过程。

  • 物化表存储子查询结果集的临时表

    • 基于内存的物化表哈希索引

    • 基于磁盘的物化表B+树索引

    • 正因为物化表中的记录都建立了索引,通过索引来判断某个操作数是否存在子查询结果集中时,速度会变得非常快,从而提升了子查询语句的性能。

第14章 基于规则的优化(内含子查询优化)

14.1 条件化简

  1. 移除不必要的括号

  2. 常量传递

  3. 移除没用的条件

  4. 表达式计算

  5. HAVING子句和WHERE子句合并

    • 如果查询语句中没有出现聚集函数及GROUP BY子句,则可合并。
  6. 常量表检测

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

14.2 外连接消除

  1. 外连接 和 内连接 本质区别:

    • 对于外连接的驱动表的记录来说,如果无法在被驱动表中找到匹配ON子句中过滤条件的记录,那么该驱动表记录仍然会被加入到结果集中,对应的被驱动表记录的各个字段使用NULL值填充;

    • 而内连接的驱动表的记录如果无法在被驱动表中找到匹配ON子句中过滤条件的记录,那么该驱动表记录会被舍弃。

  2. 空值拒绝(reject-NULL):在外连接查询中,指定的WHERE子句中包含被驱动表中的列不为NULL值条件称为空值拒绝。

    • 即:显式指定被驱动表的某个列符合 IS NOT NULL,或者,隐含点,直接指定被驱动表的某个列符合指定的值,此时就能将 外连接 转为 内连接。

      select * from t1 left join t2 on t1.m1=t2.m2 where t2.n2 is not NULL;
      # 等价于
      select * from t1 inner join t2 on t1.m1 = t2.m2;
      
      select * from t1 left join t2 on t1.m1=t2.m2 where t2.n2 = 2;
      # 直接指定'被驱动表的某个列'符合指定的值,此时就能将 外连接 转为 内连接。
      
  3. 在被驱动表的WHERE子句符合空值拒绝的条件后,外连接和内连接可以相互转换。

  4. 好处:优化器通过评估表的不同连接顺序的成本,选出成本最低的连接顺序执行查询。

14.3 子查询优化

14.3.1 子查询语法

  1. 子查询可以在一个外层查询的各种位置出现。

    • 在SELECT子句中

    • 在FROM子句中

    • 在WHERE 或 ON子句中

    • 在 ORDER BY 子句 和 GROUP BY子句中,虽然语法支持,但无意义。

  2. 按照返回结果集区分子查询:

    • 标量子查询:只返回一个单一值的子查询。

    • 行子查询:返回一条记录的子查询(一条记录可能包含多个列)。

    • 列子查询:查出一个列的数据(这个列可能包含多条记录)。

    • 表子查询:子查询的结果既包含很多条记录,又包含很多个列。

  3. 按与外层查询的关系来区分子查询:

    • 不相关子查询:子查询可以单独运行出结构,而不依赖于外城查询的值。

    • 相关子查询:子查询的执行需要依赖于外层查询的值。

  4. 子查询在布尔表达式中的使用

    1. 使用 =、>、<、>=、 <=、 <>、 !=、 <=> 作为布尔表达式的操作符

      • 注意:这里的子查询只能是标量子查询or行子查询,即,子查询的结果只能返回一个单一的值or只能是一条记录。
       # 标量子查询
       select * from t1 where m1 < (select MIN(m2 from t2); 
       
       # 行子查询
       select * from t1 where (m1,n1)=(select m2,n2 from t2 limit 1);
      
    2. [NOT] IN / ANY / SOME / ALL 子查询

    3. EXISTS子查询

  5. 子查询语法注意事项

    • 子查询必须用小括号括起来。

    • SELECT子句中的子查询必须是标量子查询(注意,不是from/where等子句)。

        # slect 子句中的子查询  是 标量子查询
        select (select m1, n1 from t1); 
        
        # where/from子句中的子查询 也可以是 行子查询
        ```
      
      
    • 想要得到标量子查询or行子查询,但又不能保证子查询的结果集只有一条记录时,应该使用 LIMIT 1 语句来限制记录数量。

    • 对于[NOT] IN / ANY / SOME / ALL 子查询来说,子查询中不允许有LIMIT语句。

      • 注意:对于[NOT] IN / ANY / SOME / ALL 子查询来说,在子查询中使用 ORDER BY子句、DISTINCT子句,以及没有聚集函数和 HAVING子句的GROUP BY 子句是无意义的。因为,子查询的结果其实相当于是一个集合,集合里的值是否排序一点也不重要。比如:

        select * from t1 where m1 in (selct m2 from t2 order by m2);
        
      • 在没有聚集函数以及HAVING子句时,GROUP BY 子句就是个摆设。比如:

        select * from t1 where m1 in (selct m2 from t2 group by m2);
        
    • 不允许在一条语句中增删改某个表的记录时,同时还对该表进行子查询。

14.3.2 子查询在MySQL中是怎么执行的

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

  1. 不相关标量/行子查询语句:独立执行外层查询和子查询(当作两个单表查询)。

  2. 相关标量/行子查询语句:例1,

    # 例1
    select * from s1 where 
        key = (select common_field from s2 where s1.key3 = s2.key3 limit 1);
    

    执行方式:

    • 步骤1:先从外层查询中获取一条记录。在例1中,先从s1表中获取一条记录。

    • 步骤2:然后从这条记录中找出子查询中涉及的值。 在例1中,从s1表中获取的那条记录中找出s1.key3列的值,然后执行子查询。

    • 步骤3:最后根据子查询的查询结果来检测外层查询WHERE子句的条件是否成立。如果成立,就把外层查询的那条记录加入到结果集,否则就丢弃。

    • 步骤4:跳到步骤1,直到外层查询中获取不到记录为止。

2. IN子查询优化

  1. 物化表的提出。

    • 物化:将子查询结果集中的记录保存到临时表的过程。

    • 物化表存储子查询结果集的临时表

      • 基于内存的物化表哈希索引

      • 基于磁盘的物化表B+树索引

      • 正因为物化表中的记录都建立了索引,通过索引来判断某个操作数是否存在子查询结果集中时,速度会变得非常快,从而提升了子查询语句的性能。

  2. 物化表转连接

    # 查询1
    select * from s1
    where key1 in (slecet common_field from s2 where key3 = 'a);
    
    # 当把子查询物化之后,假设子查询物化表的名称为 materialized_table, 
    # 该物化表存储的子查询结果集的列为 m_val。
      
    # 则相当于表s1与子查询物化表 materialized_table进行内连接。
    # 即,查询1 等价于 查询2
    
    # 查询2
    select s1.* from s1 
    inner join materialized_table on key1 = m_val;
    
    • 转换为内连接之后,查询优化器可以评估不同连接顺序需要的成本是多少,然后从中选取成本最低的那种方式执行查询。

    • 分析查询2(表s1和物化表materialized_table内连接)的成本构成:

      1. 如果使用 s1表作为驱动表,总查询成本如下:
      • 物化子查询时需要的成本;

      • 扫描s1表时的成本;

      • s1表中的记录数量 x 通过条件 m_val=xxx 对 materialized_table表进行单表访问的成本(由于物化表中的记录时不重复的,并且为物化表中的列建立了索引,所以此步骤非常快)。

      1. 如果使用 materialized_table 表作为驱动表,总查询成本如下:
      • 物化子查询时需要的成本;

      • 扫描物化表时的成本;

      • 物化表中的记录数量 x 通过条件 key1=xxx 对 s1 表进行单表访问的成本(由于在key1列上建立了索引,所以此步骤非常快)。

  3. 将子查询转换为半连接

    将子查询物化之后再执行查询,会有建立临时表的成本,那,能不能不进行物化操作,直接把子查询转换为连接呢?

    # 查询1
    select * from s1
    where key1 in (slecet common_field from s2 where key3 = 'a);
    
    • 提出新概念——半连接

    • 注意:半连接,是为了 IN子查询优化 的。

    • 将 s1表和s2表进行半连接的意思是:

      • 对于s1表中的某条记录来说,我们只关心在s2表中是否存在与之匹配的记录,而不关心具体由多少条记录与之匹配,最终的结果集中只保留s1表的记录。

      • # 半连接,只是在MySQL内部采用的一种执行子查询的方式,
        # MySQL没有提供面向用户的半连接语法。
        # 所以此语句不能放在黑框框中运行。
        select s1.* from s1 SEMI JOIN s2
            on s1.key1 = s2.common_field
            where key3 = 'a';
        
    • 实现 半连接 方法(策略):

      • Table pullout (子查询中的表上拉)

      • Duplicate Weedout (重复值消除)

      • LooseScan(松散扫描)

      • Semi-join Materialization(半连接物化)

      • FirstMatch(首次匹配)

    • 半连接的适用条件 (只有符合下述条件的子查询才可以转换为半连接)

      • 该子查询必须是与IN操作符组成的布尔表达式,并且在外城查询的WHERE 或者ON子句中出现;

      • 外层查询也可以由其他的搜索条件,只不过必须使用AND操作符与IN子查询的搜索条件连接起来;

      • 该子查询必须是一个单一的查询,不能是由UNION连接起来的若干个查询;

      • 该子查询不能包含GROUP BY、HAVING语句或者聚集函数。

    • 不适用于半连接的情况

      • 在外层查询的WHERE子句中,存在其他搜索条件使用OR操作符与IN子查询组成的布尔表达式连接起来的情况。

      • 使用 NOT IN 而不是 IN 的情况。

      • 位于 SELECT 子句中的 IN 子查询的情况。

      • 子查询中包含 GROUP BY 、HAVING 或者 聚集函数的情况。

      • 子查询中包含 UNION 的情况。

      • 对于不相关的子查询,可以尝试把它们物化之后再参与查询。

      • 无论子查询是相关的还是不相关的,都可以把 IN 子查询尝试转为 EXISTS 子查询。

    • 小结

      • 如果 IN 子查询符合转换为半连接的条件,查询优化器会优先把该子查询转换为半连接,再考虑下面5种执行半连接的策略中哪个的成本最低,最后从中选择成本最低的执行策略来执行子查询。

        • Table pullout (子查询中的表上拉)

        • Duplicate Weedout (重复值消除)

        • LooseScan(松散扫描)

        • Semi-join Materialization(半连接物化)

        • FirstMatch(首次匹配)

      • 如果 IN 子查询不符合转换为半连接的条件,那么查询优化器会从下面两种策略中找出一种成本更低的方式来执行子查询:

        • 先将子查询物化,再执行查询;

        • 执行 IN 到 EXISTS 的转换。

3. ANY / ALL 子查询优化

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qxlXmvU4-1683462178280)(C:\Users\YUE\AppData\Roaming\marktext\images\2023-05-07-19-57-24-image.png)]

4. [NOT] EXISTS 子查询的执行

5. 对于派生表的优化

  1. 派生表:放在FROM子句后面的子查询称为派生表。

  2. 对于含有派生表的查询,MySQL提供了两种执行策略。

  • 把派生表物化

    • 思想:将派生表的结果集写到一个内部的临时表(物化表)中,把此物化表当作普通表一样来参与查询。

    • 延迟物化策略:在查询中真正使用到派生表时,才会去尝试物化派生表,而不是在执行查询之前就先把派生表物化。

  • 将派生表和外层查询合并(即,将查询 重写为 没有派生表的形式)

——读书笔记,摘自《MySQL是怎样运行的》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/499651.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

UDP报头、TCP报头、IP报头、MAC头部、ARP头部

前言&#xff1a;DUP报头、TCP报头、IP报头、MAC头部、ARP头部。 UDP报头&#xff1a; UDP报头由八个字节组成&#xff0c;每个字段都是两个字节 &#xff1a; 1.源端口号&#xff1a;发送方端口号&#xff0c;需要对方回信的时候选用&#xff0c;不需要对方回信的时候置0 …

[LeetCode复盘] LCCUP‘23春季赛组队赛 20230507

[LeetCode复盘] LCCUP23春季赛组队赛 20230507 一、本周周赛总结1. 符文储备1. 题目描述2. 思路分析3. 代码实现 2. 城墙防线1. 题目描述2. 思路分析3. 代码实现 3. 提取咒文1. 题目描述2. 思路分析3. 代码实现 4. 生物进化录1. 题目描述2. 思路分析3. 代码实现 5. 与非的谜题…

HNU-操作系统OS-实验Lab3

OS_Lab3_Experimental report 湖南大学信息科学与工程学院 计科 210X wolf &#xff08;学号 202108010XXX&#xff09; 实验目的 了解虚拟内存的Page Fault异常处理实现了解页替换算法在操作系统中的实现 实验内容 本次实验是在lab2的基础上&#xff0c;借助于页表机制…

【python数据分析】运算符与表达式

&#x1f64b;‍ 哈喽大家好&#xff0c;本次是python数据分析、挖掘与可视化专栏第三期 ⭐本期内容&#xff1a;运算符与表达式 &#x1f3c6;系列专栏&#xff1a;Python数据分析、挖掘与可视化 &#x1f44d;保持开心&#xff0c;拒绝拖延&#xff0c;你想要的都会有&#x…

车载软件架构——闲聊几句AUTOSAR BSW(四)

我是穿拖鞋的汉子,魔都中坚持长期主义的工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 我们并不必要为了和谐,而时刻保持通情达理;我们需要具备的是,偶尔有肚量欣然承认在某些方面我们可能会有些不可理喻。该有主见的时候能掷地有声地镇得住场…

iOS 对https App内部的http请求进行白名单设置

苹果从iOS9开始要求应用使用Https链接来对请求进行加密,来保证数据的安全.如果使用http请求将会报错,当然,如果你想继续使用http请求,有两种方式: 1.使用ASIHttpRequest来请求,ASI是使用CFNetwork来处理请求的,更底层些,避开了苹果的限制 2.在Info.plist文件设置如下 <key…

Docker安装常用软件-Apollo(有问题)

零&#xff1a;apollo概念介绍 官网网站&#xff1a;GitHub - apolloconfig/apollo: Apollo is a reliable configuration management system suitable for microservice configuration management scenarios. gitee网址&#xff1a;mirrors / ctripcorp / apollo GitCode …

自学软件测试简历没项目写怎么办?

目录 一、引言 二、测试任务 三、测试进度 四、测试资源 五、测试策略 六、测试完成标准 七、风险和约束 八、问题严重程度描述和响应时间规范 九、测试的主要角色和职责 软件测试是使用人工或者自动的手段来运行或者测定某个软件系统的过程&#xff0c;其目的在于检验…

Python:Python进阶:Python字符串驻留技术

Python字符串驻留技术 1.什么是字符串驻留2. 为什么要驻留字符串3. Python的字符串驻留4. Python 字符驻留原理4.1 如何驻留字符串4.2 如何清理驻留的字符串 5. 字符串驻留的实现5.1. 变量、常量与函数名5.2 字典的键5.3 任何对象的属性5.4 显式地驻留 6 字符串驻留的其他发现 …

MySQL --- DML

接下来学习第二个部分&#xff1a;根据页面原型以及需求进行相关功能的开发&#xff0c;进而完成数据库的操作。 学习数据库的DML操作 3. 数据库操作-DML-insert&#xff0c;update,delete DML DML英文全称是Data Manipulation Language(数据操作语言)&#xff0c;用来对数据…

176_工具_Power BI 实用工具 pbi-utils 更新至 v1.0.3.1

176_工具_Power BI 实用工具 pbi-utils 更新至 v1.0.3.1 pbi-utils 更新至&#xff1a;v1.0.3.1, 从 v1.0.0.0 到 v1.0.3.1 更新了 8 次。 文档地址&#xff1a;https://jiaopengzi.com/2880.html 主要功能&#xff1a; 快速设置 Power BI 模板&#xff0c;实现高复用。设计…

【大数据基础】Spark+Kafka构建实时分析Dashboard

https://dblab.xmu.edu.cn/post/spark-kafka-dashboard/ https://dblab.xmu.edu.cn/post/8116/ 实验环境准备 Kafka安装 访问Kafka官方下载页面,下载稳定版本0.10.1.0的kafka.此安装包内已经附带zookeeper,不需要额外安装zookeeper.按顺序执行如下步骤: cd ~/下载 sudo tar …

《Markdown编辑器》的使用

这里写自定义目录标题 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个…

Simulink 自动代码生成电机控制:方波高频注入仿真到代码生成开发板演示

目录 前言 方波高频注入仿真 生成代码开发板运行 总结 前言 最近换了一个小电机&#xff0c;于是尝试了一下方波高频注入的仿真到代码生成的实验&#xff0c;正弦波注入的方式已经实现 STM32 Simulink 自动代码生成电机控制——脉振高频注入_高频注入代码_卡洛斯伊的博客-…

【Linux】进程信号(下)

文章目录 1.信号处理相关问题内核态与用户态概念的理解为什么要有 用户态和内核态CR3寄存器的使用信号处理的整体过程 1.信号处理相关问题 信号处理&#xff0c;不是可以立即处理的&#xff0c;而是在合适的时候 不懂点击: 信号的产生第三点 什么时候是合适的时候&#xff1f;…

Android Studio下载及安装和Gradle的配置

文章目录 下载安装双击打开exe文件 修改Sdk的位置创建项目修改Gradle的位置 下载 下载地址&#xff1a;官方下载地址 打开后往下拉&#xff0c;直到最后的I agree to the terms. 这里选择的android studio版本是&#xff1a;2021.2.1.16&#xff0c;也可以根据自己的需要下载…

语义分割总结

文章目录 0. 前言1. 数据集2. 经典网络2.1 FCN2.2 U-Net2.3 DeepLab2.4 PSPNet2.5 SegNet2.6 CCNet2.7 SegFormer 3. 损失函数4. 评价指标5. 最新进展&#xff08;2023.4&#xff09; Segment Anything 0. 前言 语义分割是一种计算机视觉领域的图像分割技术&#xff0c;旨在将…

校内赛WP

Web题目镜像如下&#xff1a; docker pull lauaiwin/hzuctf-flaskrce:latest docker pull lauaiwin/hzuctf-ezphp:latest docker pull lauaiwin/hzuctf-babysql:latest docker pull lauaiwin/hzuctf-sign:latest docker pull lauaiwin/hzuctf-ezupload:latestWeb-签到 通过loc…

sentinel 随笔 2-降级处理

0. 像喝点东西&#xff0c;但不知道喝什么 先来段源码&#xff0c;看一下 我们在dashboard 录入的降级规则&#xff0c;都映射到哪些字段上 package com.alibaba.csp.sentinel.slots.block.degrade;public class DegradeRule extends AbstractRule {public DegradeRule(String…