mysql之规则优化器RBO

文章目录

  • MySQL 基于规则的优化 (RBO):
    • RBO 的核心思想:模式匹配与规则应用
    • RBO 的主要优化规则
      • 查询重写 (Query Rewrite) / 查询转换 (Query Transformation)
        • 子查询优化 (Subquery Optimization) - RBO 的重中之重
          • 非相关子查询 (Non-Correlated Subquery) 优化
          • 相关子查询 (Correlated Subquery) 的优化 (有限的 RBO 优化)
        • 视图合并 (View Merging)
        • 条件化简 (Predicate Simplification)
        • 外连接消除 (Outer Join Elimination)
        • 其他查询重写规则
      • 访问路径选择 (Access Path Selection) - RBO 的早期角色 (现在更多由 CBO 负责)
      • JOIN 顺序优化 (Join Order Optimization) - RBO 的早期角色 (现在更多由 CBO 负责)
    • RBO vs. CBO:各有千秋,协同工作
    • RBO 的局限性与 CBO 的优势
    • RBO 优化指导与实践建议
    • 子查询优化
      • 子查询语法
        • 按返回结果集区分
        • 按与外层查询关系区分
      • 子查询在布尔表达式中的使用
      • 子查询在 MySQL 中的执行方式
    • 实战优化技巧
      • IN vs EXISTS选择
      • 派生表优化
    • 优化验证工具
    • 实际使用建议
    • 总结

MySQL 基于规则的优化 (RBO):

MySQL 查询优化器除了成本优化 (CBO) 外,还包含一套基于规则的优化 (Rule-Based Optimization, RBO) 策略。RBO 就像 SQL 查询的 “整形医生”,依据预定义的规则,对查询进行快速的语法和语义转换,提升查询效率。

RBO 的核心思想:模式匹配与规则应用

RBO 的核心是 模式匹配 (Pattern Matching) 与规则应用 (Rule Application)。优化器预定义了一系列优化规则, 描述特定 SQL 模式的优化转换方式。优化器解析 SQL 查询时, 会尝试将查询与 RBO 规则进行匹配。如果匹配成功,则应用规则,对查询进行改写, 生成一个语义等价但可能更高效的新查询。

RBO 的主要优化规则

查询重写 (Query Rewrite) / 查询转换 (Query Transformation)

这是 RBO 最核心的功能,通过改写 SQL 语句本身来优化。

子查询优化 (Subquery Optimization) - RBO 的重中之重

子查询是常见的性能瓶颈。RBO 针对不同类型的子查询,应用不同的优化规则。

非相关子查询 (Non-Correlated Subquery) 优化

子查询的执行不依赖于外部查询的表。RBO 倾向于将非相关子查询 物化 (Materialization)转换为连接 (Unnesting)

  • IN** 子查询转换为 **JOIN** (Subquery Unnesting - IN to JOIN)😗* 将 WHERE column IN (SELECT ...) 形式的非相关 IN 子查询,转换为等价的 INNER JOINLEFT SEMI JOIN

-- 原始 SQL (IN 子查询)SELECT * FROM orders WHERE customer_id IN (SELECT customer_id FROM customers WHERE region = 'North');-- RBO 转换后的 SQL (JOIN)SELECT o.* FROM orders oINNER JOIN customers c ON o.customer_id = c.customer_idWHERE c.region = 'North';

机制详解: RBO 识别出 IN 子查询是非相关的,并且子查询的目的是过滤 orders 表的 customer_id。 因此,它将子查询提取出来,与外部查询的 orders 表进行 INNER JOIN 连接,连接条件是 o.customer_id = c.customer_id。 WHERE c.region = ‘North’ 条件被保留。

SELECT * FROM orders o WHERE o.customer_id IN (SELECT c.customer_id FROM customers c WHERE c.coutry=o.contry);

注:当子查询引用了外部查询的列时(相关子查询),其结果依赖于外部查询的每一行,外部查询每一行都需要执行一次子查询,非相关子查询

  • EXISTS** 子查询转换为 **JOIN** (Subquery Unnesting - EXISTS to JOIN)😗* 将 WHERE EXISTS (SELECT ...) 形式的非相关 EXISTS 子查询,转换为 LEFT SEMI JOIN

-- 原始 SQL (EXISTS 子查询)SELECT * FROM departments WHERE EXISTS (SELECT * FROM employees WHERE dept_id = departments.dept_id AND salary > 100000);-- RBO 转换后的 SQL (LEFT SEMI JOIN)SELECT d.* FROM departments dLEFT SEMI JOIN employees e ON d.dept_id = e.dept_id AND e.salary > 100000;

机制详解: EXISTS 子查询用于判断是否存在满足条件的记录。 RBO 将其转换为 LEFT SEMI JOIN,LEFT SEMI JOIN 只返回左表 (departments) 中在右表 (employees) 中找到匹配行的记录,且对于左表的每一行,右表最多返回一行。 ON 子句中包含了连接条件 d.dept_id = e.dept_id 和子查询的过滤条件 e.salary > 100000。

  • 物化 (Materialization) 非相关子查询: 对于某些非相关子查询,RBO 可能会将子查询的结果 物化 为一个临时表。

-- 原始 SQL (非相关子查询多次引用)SELECT (SELECT COUNT(*) FROM orders WHERE status = 'pending') AS pending_orders,(SELECT AVG(total_amount) FROM orders WHERE status = 'completed') AS avg_completed_amount;-- RBO 可能物化子查询结果为临时表 (伪代码)CREATE TEMPORARY TABLE temp_subquery_result ASSELECT 'pending_orders' AS result_name, COUNT(*) AS result_value FROM orders WHERE status = 'pending'UNION ALLSELECT 'avg_completed_amount' AS result_name, AVG(total_amount) AS result_value FROM orders WHERE status = 'completed';SELECT result_value FROM temp_subquery_result WHERE result_name = 'pending_orders';SELECT result_value FROM temp_subquery_result WHERE result_name = 'avg_completed_amount';

机制详解: RBO 检测到两个相同的非相关子查询 (虽然 WHERE 条件不同,但表和基本结构相同)。 为了避免重复计算,RBO 可以将子查询结果预先计算出来,并存储在一个临时表中。 外部查询直接从临时表中获取结果。 注意: MySQL 实际的物化策略比这个伪代码更复杂,会考虑更多因素,例如子查询结果集大小、查询复杂度等

相关子查询 (Correlated Subquery) 的优化 (有限的 RBO 优化)

子查询的执行依赖于外部查询的表。RBO 主要尝试将某些简单的相关子查询 转换为连接

  • EXISTS** 相关子查询转换为 **JOIN** (有限的 Unnesting)😗* 某些简单的 EXISTS 相关子查询,RBO 可以尝试转换为 JOIN,例如 LEFT SEMI JOIN

-- 原始 SQL (简单的 EXISTS 相关子查询)SELECT * FROM customers c WHERE EXISTS (SELECT * FROM orders o WHERE o.customer_id = c.customer_id AND o.order_date >= '2023-01-01');-- RBO 可能转换为 (LEFT SEMI JOIN)SELECT c.* FROM customers cLEFT SEMI JOIN orders o ON o.customer_id = c.customer_id AND o.order_date >= '2023-01-01';
视图合并 (View Merging)

如果查询中使用了视图 (View),RBO 尝试将视图的定义 合并 (Merge) 到主查询中。

-- 假设定义了视图 v_customer_orders
CREATE VIEW v_customer_orders AS
SELECT c.customer_id, c.customer_name, COUNT(o.order_id) AS order_count
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
GROUP BY c.customer_id, c.customer_name;-- 查询视图
SELECT * FROM v_customer_orders WHERE order_count > 5;-- RBO 视图合并后的 SQL (伪代码)
SELECT c.customer_id, c.customer_name, COUNT(o.order_id) AS order_count
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
GROUP BY c.customer_id, c.customer_name
HAVING order_count > 5; -- 注意这里是 HAVING, 因为原视图有 GROUP BY
条件化简 (Predicate Simplification)

RBO 会尝试化简 WHERE 子句中的条件表达式。

  • 常量传递 (Constant Propagation): 将已知常量值代入表达式。

  • 死代码消除 (Dead Code Elimination): 移除永远为真或永远为假的条件。

  • 布尔代数化简 (Boolean Algebra Simplification): 应用布尔代数规则化简。

  • 移除不必要的括号

  • 等值传递(equality_propagation)

  • HAVING 子句和 WHERE 子句的合并: 若查询语句中无聚集函数及 GROUP BY 子句

  • 常量表检测

外连接消除 (Outer Join Elimination)

在某些情况下,LEFT JOINRIGHT JOIN 可以被转换为更高效的 INNER JOIN

-- 原始 SQL (LEFT JOIN)
SELECT o.*, c.* FROM orders o
LEFT JOIN customers c ON o.customer_id = c.customer_id
WHERE c.customer_id IS NOT NULL; -- 对 LEFT JOIN 右表列的非 NULL 条件-- RBO 转换为 (INNER JOIN)
SELECT o.*, c.* FROM orders o
INNER JOIN customers c ON o.customer_id = c.customer_id
WHERE c.customer_id IS NOT NULL;
其他查询重写规则

例如,DISTINCT 优化、GROUP BY 优化、ORDER BY 优化等。

访问路径选择 (Access Path Selection) - RBO 的早期角色 (现在更多由 CBO 负责)

JOIN 顺序优化 (Join Order Optimization) - RBO 的早期角色 (现在更多由 CBO 负责)

RBO vs. CBO:各有千秋,协同工作

特性基于规则的优化 (RBO)基于成本的优化 (CBO)
优化依据预定义的规则 (启发式规则)成本模型 (基于统计信息)
优化策略查询重写、简单访问路径和 JOIN 顺序选择访问路径选择、JOIN 类型和 JOIN 顺序的精细化选择 (基于成本)
优化速度相对较慢 (需要成本估算)
优化精度相对较低 (依赖规则的有效性)较高 (更准确地评估执行计划成本)
统计信息依赖低 (或不依赖)高 (依赖于准确的统计信息)
适用场景简单查询、快速优化、初步优化复杂查询、精细化优化、对性能要求高的场景
在 MySQL 中的角色初步优化、查询重写、为 CBO 优化打基础主要优化器、负责大部分优化决策

RBO 的局限性与 CBO 的优势

RBO 虽然速度快,但其优化能力受限于预定义的规则。CBO 基于成本估算,能够更全面地考虑各种因素,做出更明智的优化选择。现代 MySQL 主要依赖 CBO 进行查询优化,RBO 更多地作为辅助手段。

RBO 优化指导与实践建议

  • 编写规范的 SQL 语句: 编写符合 RBO 规则的 SQL。

  • 理解 MySQL 的 RBO 规则: 了解 MySQL RBO 主要的优化规则。

  • 关注 EXPLAIN** 执行计划:** 使用 EXPLAIN 命令分析 SQL 查询的执行计划。

  • 结合 CBO 进行优化: RBO 只是优化过程的第一步, 最终性能还是取决于CBO。

子查询优化

子查询语法

按返回结果集区分
  • 标量子查询: 只返回一个单一值的子查询。

  • 行子查询: 返回一条记录的子查询,包含多个列。

  • 列子查询: 返回一个列的数据,包含多条记录。

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

按与外层查询关系区分
  • 不相关子查询: 子查询可单独运行出结果,不依赖于外层查询的值。

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

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

  • 使用 =>< 等操作符。

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

  • EXISTS 子查询。

子查询在 MySQL 中的执行方式

  • 标量子查询、行子查询的执行方式: 不相关的标量子查询或行子查询,先单独执行子查询,再将结果作为外层查询的参数。相关的标量子查询或行子查询,按外层查询逐条执行。

  • IN 子查询优化:

    • 物化表的提出: 对于不相关的 IN 子查询,若子查询结果集较大,优化器会将子查询结果写入临时表(物化表)。

    • 物化表转连接: 将子查询物化后,可将外层查询与物化表进行内连接。

    • 将子查询转换为 semi-join: 对于符合一定条件的 IN 子查询,优化器会将其转换为 semi-join。

    • semi-join 的适用条件: 子查询必须是和 IN 语句组成的布尔表达式,且在外层查询的 WHERE 或 ON 子句中出现;外层查询可有其他搜索条件,但必须与 IN 子查询的搜索条件使用 AND 连接;子查询必须是单一查询,不能由 UNION 连接;子查询不能包含 GROUP BY、HAVING 或聚集函数等。

    • 不适用于 semi-join 的情况: 外层查询的 WHERE 条件中有其他搜索条件与 IN 子查询组成的布尔表达式使用 OR 连接;使用 NOT IN;子查询在 SELECT 子句中;子查询包含 GROUP BY、HAVING 或聚集函数;子查询包含 UNION 等。

  • ANY/ALL 子查询优化: 不相关的 ANY/ALL 子查询在很多场合可转换为其他形式执行, 如 < ANY (SELECT inner_expr ...) 可转换为 < (SELECT MAX(inner_expr) ...)

  • [NOT] EXISTS 子查询的执行: 不相关的 [NOT] EXISTS 子查询,先执行子查询,得出结果后再重写外层查询。相关的 [NOT] EXISTS 子查询,按逐条执行的方式进行。

  • 对于派生表的优化: 将子查询放在外层查询的 FROM 子句中,子查询的结果相当于一个派生表。优化器会尝试将派生表与外层查询合并,若无法合并,则将派生表物化为临时表。

实战优化技巧

IN vs EXISTS选择

场景推荐写法原因
外层结果集大EXISTS可快速短路判断
内层结果集小IN物化成本低
需要结果去重IN + DISTINCT利用物化表的自动去重特性

派生表优化

-- 原始查询
SELECT * FROM (SELECT dept_id, AVG(salary) avg_sal FROM employees GROUP BY dept_id
) AS dept_sal 
WHERE avg_sal > 10000;-- 优化手段:
SET optimizer_switch = 'derived_merge=on'; -- 启用派生表合并

优化验证工具

-- 查看优化器决策过程
SET optimizer_trace="enabled=on";
SELECT * FROM users WHERE id IN (SELECT user_id FROM orders);
SELECT * FROM information_schema.OPTIMIZER_TRACE;
SET optimizer_trace="enabled=off";

实际使用建议

  1. 对于关联子查询,确保被驱动表的连接列有索引。

  2. 大数据集IN查询优先测试物化表性能。

  3. 使用EXPLAIN FORMAT=JSON分析执行计划细节。

  4. 定期更新统计信息保证优化器决策准确。

总结

MySQL 基于规则的优化 (RBO) 是查询优化器中不可或缺的一部分。它通过快速的模式匹配和规则应用,对 SQL 查询进行初步的 “整形美容”,提升查询的可读性和执行效率。虽然 RBO 的优化能力相对有限,但它仍然是现代 MySQL 优化器的重要组成部分,与 CBO 协同工作, 共同打造高效的数据库查询引擎。

参考:https://relph1119.github.io/mysql-learning-notes/#/mysql ,推荐理解本文之后去看原书,原书有一定深度需前后贯穿仔细理解

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Docker Network

1.简介 容器之间的通讯时通过网桥通讯的&#xff0c;跨主机通讯可以使用flannel进行通讯 那么为什么主机可以访问到虚拟机内部呢&#xff1f;因为VMware虚拟出一个虚拟的网卡&#xff0c;而这个虚拟网卡和主机在同一个局域网下 NAT是映射一个虚拟网卡&#xff0c;进行路由通信…

【Linux系统】—— 冯诺依曼体系结构与操作系统初理解

【Linux系统】—— 冯诺依曼体系结构与操作系统初理解 1 冯诺依曼体系结构1.1 基本概念理解1.2 CPU只和内存打交道1.3 为什么冯诺依曼是这种结构1.4 理解数据流动 2 操作系统2.1 什么是操作系统2.2 设计OS的目的2.3 操作系统小知识点2.4 如何理解"管理"2.5 系统调用和…

【行业解决方案篇十八】【DeepSeek航空航天:故障诊断专家系统 】

引言:为什么说这是“航天故障终结者”? 2025年春节刚过,航天宏图突然官宣"DeepSeek已在天权智能体上线",这个搭载在卫星和空间站上的神秘系统,号称能提前48小时预判99.97%的航天器故障。这不禁让人想起年初NASA禁用DeepSeek引发的轩然大波,更让人好奇:这套系…

计算机网络真题练习(高软29)

系列文章目录 计算机网络阶段练习 文章目录 系列文章目录前言一、真题练习总结 前言 计算机网络的阶段练习题&#xff0c;带解析答案。 一、真题练习 总结 就是高软笔记&#xff0c;大佬请略过&#xff01;

从猜想终结到算法革新,弹性哈希开启数据存储新篇章

目录 哈希表的前世今生基本原理从传统到现代:哈希表的演变历程安德鲁 克拉皮文及其团队的创作历程弹性哈希详解基本原理优点技术细节漏斗哈希解析基本原理优点技术细节新算法的实际应用案例电子商务推荐系统金融交易监控系统社交媒体内容过滤物联网设备管理结论与展望哈希表的…

DeepSeek各模型现有版本对比分析

文章目录 一、基础模型系列&#xff1a;V1 到 V3 的演进二、专用模型系列&#xff1a;推理与多模态三、版本选型与商业化趋势 DeepSeek作为最近特别火爆的模型&#xff0c;本文将对DeepSeek现有的主要版本进行对比分析,涵盖参数规模、训练数据、功能改进、应用场景和性能表现等…

RabbitMQ学习—day6—springboot整合

目录 1. springboot配置 2. 开始写RabbitMq代码 3. 队列优化 4. 插件实现延迟队列 5. 总结 前一小节我们介绍了死信队列&#xff0c;刚刚又介绍了 TTL&#xff0c;至此利用 RabbitMQ 实现延时队列的两大要素已经集齐&#xff0c;接下来只需要将它们进行融合&#xff0c;再加…

Automa 浏览器自动化编排 实现自动化浏览器操作

在日常的浏览器使用过程中&#xff0c;我们常常会遇到一些重复繁琐的任务&#xff0c;比如反复填写网页表单、从网页抓取数据、定时截图等&#xff0c;这些工作不仅耗费时间和精力&#xff0c;还容易出错。今天要给大家介绍的Automa&#xff0c;就是一款专门用来解决这类问题的…

【多模态处理篇五】【DeepSeek文档解析:PDF/Word智能处理引擎】

你知道吗?全球每天产生的PDF文档超过10亿份,但90%的上班族还在用复制粘贴的笨办法处理文档!DeepSeek文档解析引擎就像给你的电脑装上了"文档翻译官",能把PDF/Word里的文字、表格、公式甚至排版样式都变成AI能理解的"语言"。举个真实场景:法务小姐姐用…

【C语言】结构体内存对齐问题

1.结构体内存对齐 我们已经基本掌握了结构体的使用了。那我们现在必须得知道结构体在内存中是如何存储的&#xff1f;内存是如何分配的&#xff1f;所以我们得知道如何计算结构体的大小&#xff1f;这就引出了我们今天所要探讨的内容&#xff1a;结构体内存对齐。 1.1 对齐规…

【多模态处理篇三】【DeepSeek语音合成:TTS音色克隆技术揭秘】

最近帮某明星工作室做AI语音助手时遇到魔幻需求——要求用5秒的咳嗽声克隆出完整音色!传统TTS系统直接翻车,生成的语音像得了重感冒的电音怪物。直到祭出DeepSeek的TTS音色克隆黑科技,才让AI语音从"机器朗读"进化到"声临其境"。今天我们就来扒开这个声音…

IDEA使用Maven方式构建SpringBoot项目

1、环境准备 确保你已经安装了以下工具&#xff1a; Java JDK&#xff08;推荐 JDK 8 或更高版本&#xff09; IntelliJ IDEA&#xff08;推荐使用最新版本&#xff09; 2、创建 Spring Boot 项目 &#xff08;1&#xff09; 打开 IntelliJ IDEA。 &#xff08;2&#xff09…

【Redis原理】底层数据结构 五种数据类型

文章目录 动态字符串SDS(simple dynamic string )SDS结构定义SDS动态扩容 IntSetIntSet 结构定义IntSet的升级 DictDict结构定义Dict的扩容Dict的收缩Dict 的rehash ZipListZipListEntryencoding 编码字符串整数 ZipList的连锁更新问题 QuickListQuickList源码 SkipListRedisOb…

Git Repo下如何制作一个patch文件

Git Repo下如何制作一个patch文件 1. 源由2. 步骤2.1 本地代码差异2.2 添加修改代码2.3 添加未跟踪代码2.4 确认打包文件2.5 输出打包文件2.6 自查打包文件2.7 恢复工作环境 3. 总结 1. 源由 patch分享&#xff0c;更好的差异化比较&#xff0c;减少时间浪费。同时&#xff0c…

跟着李沐老师学习深度学习(十四)

注意力机制&#xff08;Attention&#xff09; 引入 心理学角度 动物需要在复杂环境下有效关注值得注意的点心理学框架&#xff1a;人类根据随意线索和不随意线索选择注意力 注意力机制 之前所涉及到的卷积、全连接、池化层都只考虑不随意线索而注意力机制则显示的考虑随意…

STM32的“Unique device ID“能否修改?

STM32F1系列的"Unique device ID"寄存器的地址为0x1FFFF7E8。 这个寄存器是只读的。 "Unique device ID"寄存器位于“System memory”中。“System memory”地址范围为“0x1FFF F000- 0x1FFF F7FF”。 所有STM32 MCU上都存在系统引导加载程序。顾名思义&a…

模型思维 - 领域模型的应用与解析

文章目录 引言模型的核心作用与价值四大模型类型UML建模工具UML类图的核心价值类关系深度剖析企业级建模实践 领域模型&#xff08;推荐&#xff09; vs 数据模型&#xff08;不推荐&#xff09;区别联系错把领域模型当数据模型错误方案 vs 正确方案对比正确方案的实现1. 数据库…

基于GWO灰狼优化的WSN网络最优节点部署算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 无线传感器网络&#xff08;Wireless Sensor Network, WSN&#xff09;由大量分布式传感器节点组成&#xff0c;用于监测物理或环境状况。节点部署是 WSN 的关键问…

产品概念的提出

产品概念的提出 一个产品或者一个产品概念idea是怎么想到的呢&#xff1f;很多情况下它其实来自生活中的一些不爽、不满意、想吐槽&#xff0c;凡是用户抱怨的事情就是用户的强烈刚需需求是我们要去做的事情。当有了一个想法时需要弄清楚一下几个问题&#xff1a; 核心用户事…

3.Docker常用命令

1.Docker启动类命令 1.启动Docker systemctl start docker 2.停止Docker systemctl stop docker 3.重启Docker systemctl restart docker 4.查看Docker状态 systemctl status docker 5.设置开机自启(执行此命令后每次Linux重启后将自启动Docker) systemctl enable do…