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 o

INNER JOIN customers c ON o.customer_id = c.customer_id

WHERE 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 d

LEFT 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 AS

SELECT 'pending_orders' AS result_name, COUNT(*) AS result_value FROM orders WHERE status = 'pending'

UNION ALL

SELECT '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 c

LEFT 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 ,推荐理解本文之后去看原书,原书有一定深度需前后贯穿仔细理解

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

election靶机渗透测试

发现靶机ip地址 使用nmap进行扫描端口发现详细信息nmap -T4 -sV -sC -p- 192.168.52.142 用dirsearch扫一下网站的目录 看到一个phpinfo 一个phpmyadmin的登录页面 robots.txt文件 看一下这个election目录下并没有发现什么 继续进行目录扫描&#xff0c;这时候看到一个admin的l…

为AI聊天工具添加一个知识系统 之119 详细设计之60 圣灵三角形和Checker 之2

本文要点 要点回顾 我们回顾一下本题目的讨论内容。 我的想法是&#xff0c; 将Substance 作为 面向服务的架构的起点并基于差异来自下而上地分类 实体--目的是实体职责单一化&#xff0c;将Object作为面向对象的语义差异的系统原点 并沿着差异继承的路径来至上而下地划分对…

安全生产月安全知识竞赛主持稿串词

女:尊敬的各位领导、各位来宾 男:各位参赛选手、观众朋友们 合:大家好&#xff5e; 女:安全是天&#xff0c;有了这一份天&#xff0c;我们的员工就会多一份幸福&#xff0c; 我们的企业就会多一丝光彩。 男:安全是地&#xff0c;有了这一片地&#xff0c;我们的员工就多了一…

五、Three.js顶点UV坐标、纹理贴图

一部分来自1. 创建纹理贴图 | Three.js中文网 &#xff0c;一部分是自己的总结。 一、创建纹理贴图 注意&#xff1a;把一张图片贴在模型上就是纹理贴图 1、纹理加载器TextureLoader 注意&#xff1a;将图片加载到加载器中 通过纹理贴图加载器TextureLoader的load()方法加…

Deepin(Linux)安装MySQL指南

1.下载 地址&#xff1a;https://downloads.mysql.com/archives/community/ 2.将文件解压到 /usr/local 目录下 先cd到安装文件所在目录再解压&#xff0c;本机是cd /home/lu01/Downloads sudo tar -xvJf mysql-9.2.0-linux-glibc2.28-x86_64.tar.xz -C /usr/local3.创建软链…

[MDM 2024]Spatial-Temporal Large Language Model for Traffic Prediction

论文网址&#xff1a;[2401.10134] Spatial-Temporal Large Language Model for Traffic Prediction 论文代码&#xff1a;GitHub - ChenxiLiu-HNU/ST-LLM: Official implementation of the paper "Spatial-Temporal Large Language Model for Traffic Prediction" …

Aseprite绘画流程案例(1)——画相机图标

原图&#xff1a; 步骤一&#xff1a;打开需要参照的图标 步骤二&#xff1a;将参照的图片拖放到右边&#xff0c;作为参考 步骤三&#xff1a;新建24x24的画布&#xff0c;背景为白色的画布 步骤四&#xff1a;点击菜单栏——视图——显示——像素网格&#xff08;如果画布已经…

计算机毕业设计SpringBoot+Vue.js母婴商城(源码+LW文档+PPT+讲解+开题报告)

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

Springboot + Ollama + IDEA + DeepSeek 搭建本地deepseek简单调用示例

1. 版本说明 springboot 版本 3.3.8 Java 版本 17 spring-ai 版本 1.0.0-M5 deepseek 模型 deepseek-r1:7b 需要注意一下Ollama的使用版本&#xff1a; 2. springboot项目搭建 可以集成在自己的项目里&#xff0c;也可以到 spring.io 生成一个项目 生成的话&#xff0c;如下…

Android输入事件传递流程系统源码级解析

1. 硬件层到Linux内核 设备节点&#xff1a;触摸事件由内核驱动捕获&#xff0c;写入/dev/input/eventX。关键结构体&#xff1a;input_event&#xff08;包含时间戳、类型、代码、值&#xff09;。 2. Native层处理&#xff08;system_server进程&#xff09; 2.1 EventHub …

贪心算法

int a[1000], b5, c8; swap(b, c); // 交换操作 memset(a, 0, sizeof(a)); // 初始化为0或-1 引导问题 为一个小老鼠准备了M磅的猫粮&#xff0c;准备去和看守仓库的猫做交易&#xff0c;因为仓库里有小老鼠喜欢吃的五香豆&#xff0c;第i个房间有J[i] 磅的五香豆&#xf…

HDFS Java 客户端 API

一、基本调用 Configuration 配置对象类&#xff0c;用于加载或设置参数属性 FileSystem 文件系统对象基类。针对不同文件系统有不同具体实现。该类封装了文件系统的相关操作方法。 1. maven依赖pom.xml文件 <dependency><groupId>org.apache.hadoop</groupId&g…

Scrum方法论指导下的Deepseek R1医疗AI部署开发

一、引言 1.1 研究背景与意义 在当今数智化时代&#xff0c;软件开发方法论对于项目的成功实施起着举足轻重的作用。Scrum 作为一种广泛应用的敏捷开发方法论&#xff0c;以其迭代式开发、快速反馈和高效协作的特点&#xff0c;在软件开发领域占据了重要地位。自 20 世纪 90 …

网络工程知识笔记

1. 什么是网络&#xff1f; 网络是由多个节点&#xff08;如计算机、打印机、路由器等&#xff09;通过物理或逻辑连接组成的系统&#xff0c;用于数据的传输和共享。这些节点可以通过有线&#xff08;如以太网&#xff09;或无线&#xff08;如 Wi-Fi&#xff09;方式进行连接…

qt项目配置部署

Test项目: 子项目testFileHelper 1.新建一个test项目的子项目:取名testFileHelper 2.编写测试用例 3.pro文件中引入qosbrowser 4.引入测试对象的cpp和头文件 2.在项目中引入资源文件testfile.txt,在其中输入abc 实现thrid目录复用 移动thrid 将thrild目录统一放在章…

1.1 go环境搭建及基本使用

golang下载地址&#xff1a; Download and install - The Go Programming Language (google.cn) 验证安装是否成功&#xff1a; go version 查看go环境 go env 注意&#xff1a;Go1.11版本之后无需手动配置环境变量,使用go mod 管理项目&#xff0c;也不需要把项目放到GO…

ProfiNet转EtherNet/IP攻克罗克韦尔PLC与光伏电站监控系统连接难题的通讯配置技术

、案例背景 在新能源产业蓬勃发展的当下&#xff0c;大型光伏电站作为绿色能源的重要输出地&#xff0c;其稳定高效的运行至关重要。某大型光伏电站占地面积广阔&#xff0c;内部设备众多&#xff0c;要保障电站的稳定运行&#xff0c;对站内各类设备进行集中监控与管理必不可少…

常用网络工具分析(ping,tcpdump等)

写在前面 本文看下常用网络工具。 1&#xff1a;ping 1.1&#xff1a;用途 用于检验网络的连通性。 1.2&#xff1a;实战 在Linux环境中执行&#xff1a;ping www.sina.com.cn&#xff1a; [rootlocalhost ~]# ping www.sina.com.cn PING spool.grid.sinaedge.com (111.…

windows系统本地部署DeepSeek-R1全流程指南:Ollama+Docker+OpenWebUI

本文将手把手教您使用OllamaDockerOpenWebUI三件套在本地部署DeepSeek-R1大语言模型&#xff0c;实现私有化AI服务搭建。 一、环境准备 1.1 硬件要求 CPU&#xff1a;推荐Intel i7及以上&#xff08;需支持AVX2指令集&#xff09; 内存&#xff1a;最低16GB&#xff0c;推荐…

计算机网络-面试总结

计算机网络 从输入一个URL到页面加载完成的过程 整体流程 DNS查询过程SSL四次握手HTTP 的长连接与短连接 HTTP 的 GET 和 POST 区别浏览器访问资源没有响应&#xff0c;怎么排查? OSI七层参考模型 TCP/IP四层参考模型比较 TCP/IP 参考模型与 OSI 参考模型 TCP三次握手&四…