【MySQL·8.0·源码】subquery 子查询处理分析(一)

news2024/12/31 6:49:35

引言

在 SQL 中,子查询属于 Nested Query 的一种形式,根据 Kim 的分类[1],Nested Query 即嵌套查询是一种 SQL-like 形式的查询语句嵌套在另一 SQL 中,SQL-like 的嵌套子句可以出现在 SELECT、FROM 和 WHERE 子句的任意位置。

在 MySQL 中,一般把出现在 WHERE 子句中的嵌套 SQL 称为 subquery(子查询),而出现在 FROM 子句的称为 derived table,因为出现在 WHERE 子句中,最终属于 boolean factor 的一部分,目的是为了进行 FILTER 过滤记录。而出现在 FROM 子句不同,其结果最终是需要以抽象成一张虚拟表,用以与其他表进行 JOIN 操作或者用于二次计算过滤使用。

subquery 出现在 WHERE 子句中,而谓词形式一般为 [Ri.ck op Q]:

Ri 表示为第 i 张 Relation,ck 表示第 k 列,op 表示运算操作符,Q 则表示一个 SQL-like 形式的子查询

op 可以是 scalar 标量比较运算符(=、!=、>、>=、<、<=)或者是 set 集合成员运算符(IS IN,IS NOT IN、EXISTS、NOT EXISTS、ANY、ALL、SOME)。
两者的区别在于 scalar 标量运算符的右操作数总是返回单行单列值,而 set 运算符右操作数则是一个集合。
例如:

  • scalar 子查询

    select * from t1 where c1 = (select max(c1) from t2 where c2 > 25);
    
  • 普通子查询

    select * from t1 where c1 in (select c1 from t2 where c2 > 25);
    

Rule-based 转换

前面在 【MySQL·8.0·源码】MySQL 的查询处理有介绍,SQL 在 Transform 阶段会根据规则进行尝试简化,在此之前,我们必须知道子查询有以下等效规则[2]:

  1. Exists 的转换
    WHERE EXISTS (select <sel> from <tbl> where <cond>)
    
    可以被等效为
    WHERE 0 < (select count(<sel>) from <tbl> where <cond>)
    
  2. Not Exists 的转换
    WHERE NOT EXISTS (select <sel> from <tbl> where <cond>)
    
    可以被等效为
    WHERE 0 = (select count(<sel>) from <tbl> where <cond>)
    
  3. ANY 和 ALL 的转换
  • < ANY
    < ANY (select <sel> from <tbl> where <cond>)
    
    可以被等效为
    < (select MAX(<sel>) from <tbl> where <cond>)
    
  • > ANY
    > ANY (select <sel> from <tbl> where <cond>)
    
    可以被等效为
    > (select MIN(<sel>) from <tbl> where <cond>)
    
  • < ALL
    < ALL (select <sel> from <tbl> where <cond>)
    
    可以被等效为
    < (select MIN(<sel>) from <tbl> where <cond>)
    
  • > ALL
    > ALL (select <sel> from <tbl> where <cond>)
    
    可以被等效为
    > (select MAX(<sel>) from <tbl> where <cond>)
    

语法树形式

引言中介绍了子查询有以下形式:

select <selitems> from Ri where Ri.ck op <Q>

在 【MySQL·8.0·源码】MySQL 语法树基础知识 中有介绍,在 MySQL 中,<SELECT><WHERE> 子句都是使用 Item 来表示各个 expression 表达式的。
对于子查询也不例外,MySQL 通过使用一个 Item_subselect 的基类引申不同类型的子查询:
Item_subselect 基类的继承关系有:

Item_subselect
+--Item_singlerow_subselect
   +--Item_maxmin_subselect
+--Item_exists_subselect
   +--Item_in_subselect
      +--Item_allany_subselect

其中:

  • Item_singlerow_subselect 对应的是 SCALAR 子查询或者单行的子查询
  • Item_exists_subselect 对应的是 [NOT] EXISTS 的子查询
  • Item_in_subselect 对应的是 [NOT] IN 子查询
  • Item_allany_subselect 对应 <op> ALL 或者 <op> ANY 形式的子查询

引言中提到,子查询是 Nested Query 的一种形式,在【MySQL·8.0·源码】MySQL 语法树结构 中有介绍过形如另外几种形式的嵌套查询:

  • 括号嵌套查询
select * from t3, (t1, t2) where t1.c1 = t2.c2;
  • 外连接嵌套查询
select * from t1 left outer join(t2, t3) on t1.c1 = t2.c1 and t1.c2 = t3.c2 where t1.c1 = t2.c2;

它们两的语法结构形式可以回顾【MySQL·8.0·源码】MySQL 语法树结构 。

同理,子查询作为另外一种嵌套查询,在 MySQL 中也是以相同的形式进行组织,而且子查询的 WHERE 子句上也使用形如 Item_xxx_subselect 代替普通的 Item 来表示一个子查询,整体语法树结构大致为:

例如,形如一下的 IN 子查询

select * from t1 where c1 in (select c1 from t2 where c1 > 25);

在这里插入图片描述
左侧为 Parse 结束后的语法树结构,两个 Query_block 分别对应外表 t1 和子查询 t2,除了 Query_block 和 Query_expression 可以从 t1 查询找到 t2 查询外,外表 t1 还通过 where 子句 Item_in_subselect 可以找到内表子查询 Query_block(t2),两个 Query 分别都有各自的 select list,from,where 子句。

右侧为经过 Transform 转为 semi-join 之后的语法树逻辑,这时内表子查询 t2 已经被 pullout 或 Merge 到外表查询块上,而内表条件也被 merge 到外表 where 条件中,而 t1 与 t2 也称为了的一种 semi-join 形式的嵌套查询。

Scalar 子查询的处理

对于只需返回单一值的子查询,称为 Scalar 子查询
可以是 scalar 标量比较运算符(=、!=、>、>=、<、<=)和 > ALL、< ALL、> ANY、< ANY 及其拓展形式
子查询中使用聚合函数(SUM,AVG,MAX,MIN,COUNT)返回结果等
例如:

select * from t1 where c1 > (select max(c1) from t2 where c1 > 25);

Prepare

在外表查询块 Query_block::prepare 进行 resolve 时,会 resolve where 条件,尝试解析 where 条件上的 Item 列到
实际 table field 的各种引用关系,而外表查询块的 where 条件是一个子查询 item(Item_singlerow_subselect),所以
最终会尝通过 Item_singlerow_subselect::fix_fields 来解析子查询 item 到实际 field 的引用。

Item_singlerow_subselect::fix_fields()->Item_subselect::fix_fields()->query_expr()->prepare()

子查询右侧操作数实际上是一个查询 Query_block,所以 resolve 时,会进一步调用子查询 Query_block::prepare 来
进一步 resolve/transform 子查询块,直到最终实际上是引用到 max(t2.c1) field

Optimize

子查询块的 prepare 是通过外层查询块的 resolve where 子句触发的,而 optimize 则是挪到了实际 Execute 阶段,由于
scalar 子查询最终返回的是单行单列结果,所以对实际延迟到 Execute 做子查询的 optimize 没有任何影响

Execute

scalar 子查询的执行由外层查询块在 evaluate where 条件时触发,对 Item_in_select 进行 boolean factor 的校验时,
触发子查询的 optimize 和 Execute,单行单列结果存储在子查询的 <select>

Item_singlerow_subselect::val_xxx()->Item_subselect::exec()->query_expr()->optimize()
Item_singlerow_subselect::val_xxx()->Item_subselect::exec()->query_expr()->execute()

预告:下篇继续普通 set 集合运算 subquery 的处理分析

引用

  1. Kim W. On optimizing an SQL-like nested query[J]. ACM Transactions on Database Systems (TODS), 1982, 7(3): 443-469.
  2. Ganski R A, Wong H K T. Optimization of nested SQL queries revisited[J]. ACM SIGMOD Record, 1987, 16(3): 23-33.

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

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

相关文章

数据结构之最优二叉树

数据结构之最优二叉树 1、最优二叉树2、哈夫曼编码 数据结构是程序设计的重要基础&#xff0c;它所讨论的内容和技术对从事软件项目的开发有重要作用。学习数据结构要达到的目标是学会从问题出发&#xff0c;分析和研究计算机加工的数据的特性&#xff0c;以便为应用所涉及的数…

Elment UI的el-table-column表头旁边有点击按钮类似的操作

Elment UI的el-table-column表头旁边有点击按钮类似的操作 <el-table-column fixed"right" label"操作" ><!-- 表头 --> {{-- <template slot"header" header"scope">--}} {{-- <span…

uniapp设置隐藏原生导航栏(3)

1、单个页面隐藏 在pages.json里配置 (第一种方式) {"path": "pages/home/index","style": {"navigationBarTitleText": "首页","navigationStyle": "custom" // 使用自定义导航栏&#xff0c;系统会关…

在 EggJS 中实现 Redis 上锁

配置环境 下载 Redis Windows 访问 https://github.com/microsoftarchive/redis/releases 选择版本进行下载 - 勾选 [配置到环境变量] - 无脑下一步并安装 命令行执行&#xff1a;redis-cli -v 查看已安装的 Redis 版本&#xff0c;能成功查看就表示安装成功啦~ Mac brew i…

企业内部知识库搭建教程,赶紧收藏起来

在企业运营中&#xff0c;内部知识库搭建是一项重要的挑战&#xff0c;并需要合理的规划与管理。尤其对于中大型企业&#xff0c;内部知识库能够提高工作效率&#xff0c;减轻员工工作压力与突发事件的处理的困扰。下面给大家提供一份完整的内部知识库搭建教程&#xff0c;快看…

如何自信地部署人工智能(AI)

提升业务价值的人工智能方法 人工智能 (AI) 已经在变革业务、降低成本、最大限度地提高收入并增强客户体验。许多组织开始注意到&#xff1a;到 2025 年&#xff0c;AI 市场规模预计将增长到 3909 亿美元&#xff0c;而且该领域的行业也呈现出类似的发展趋势——例如&#xff…

常用界面设计组件 —— 容器组件

2.6 容器组件2.6.1 QGroupBox2.6.2 QScrollArea2.6.3 QToolBox2.6.4 QTabWidget2.6.5 QStackedWidget 2.6 容器组件 为了将界面上的各个组件的分布设计得更加美观&#xff0c;经常 使用一些容器类&#xff0c;如 QgoupBox、QtabWidget、 QToolBox等。 2.6.1 QGroupBox 实例效…

YOLOv7调用摄像头检测报错解决

yolov7detect.py文件调用本地摄像头&#xff0c;把source参数设为0 parser.add_argument(--source, typestr, default0, helpsource) # file/folder, 0 for webcam 报错&#xff1a;cv2.error: OpenCV(3.4.2) 一堆地址:The function is not implemented. Rebuild the library…

洛谷 P1705 爱与愁过火

测试用例 5 2 8 1 7 2 5 4#include<iostream> #include<string.h> using namespace std; int m, r, n; int a[100]; int visit[100] {0}; int sum 0; void traceback(int s,int price,int next){if(s r){if (price > n)sum;return ;}for (int i next ;i &…

Linux命令大全(超详细版)

一 ~ 四章 【点击此处查看】 五、shell 编程 5.1、shell 概述 5.1.1 shell 是什么 Shell是一个命令行解释器&#xff0c;它为用户提供了一个向Linux内核发送请求以便运行程序的界面系统级程序&#xff0c;用户可以用Shell来启动、挂起、停止甚至是编写一些程序。 Shell还是…

理解分布式存储的真实成本 - 10PB的硬件和软件

我们最近与一家大型银行的首席信息官进行了一次对话。他们是全球系统性重要银行之一——规模极其庞大。这位CIO决定将MinIO引入为数据分析计划的对象存储。这个部署从抵押贷款、交易和新闻平台收集数据&#xff0c;以运行Spark和其他分析工具&#xff0c;为银行提供洞察力。Min…

深入理解Java中的队列(Queue)

目录 一、什么是队列&#xff08;Queue&#xff09;&#xff1f; 二、队列中的常用方法 三、Java中的队列接口和实现类 1. LinkedList 2. ArrayDeque 3. PriorityQueue 四、队列的应用场景 1.消息队列 2.线程池任务调度 3.缓存淘汰策略 4.网络请求调度 5.广度优先搜索&#xff…

肺癌相关文献6

第十四篇 Classification of lung adenocarcinoma based on stemness scores in bulk and single cell transcriptomes IF&#xff1a;6.0 中科院分区:2区 生物学WOS分区&#xff1a;Q1被引次数&#xff1a; 4 背景&#xff1a;癌细胞具有无限期自我更新和增殖的能力[2]。在一…

# [NOI2019] 斗主地 洛谷黑题题解

[NOI2019] 斗主地 题目背景 时限 4 秒 内存 512MB 题目描述 小 S 在和小 F 玩一个叫“斗地主”的游戏。 可怜的小 S 发现自己打牌并打不过小 F&#xff0c;所以他想要在洗牌环节动动手脚。 一副牌一共有 n n n 张牌&#xff0c;从上到下依次标号为 1 ∼ n 1 \sim n 1∼…

UV紫外激光打标机的优缺点是什么

​ UV紫外激光打标机具有以下优点&#xff1a; 1. 精度高&#xff1a;紫外激光打标机的光束质量好&#xff0c;聚焦光斑小&#xff0c;可以实现在各种材料上进行超精细打标。 2. 速度快&#xff1a;由于紫外激光的独特特性&#xff0c;打标速度非常快&#xff0c;提高了生产效…

23111 C++ day1

思维导图 提示并输入一个字符串&#xff0c;统计该字符中大写、小写字母个数、数字个数、空格个数以及其他字符个数 要求使用C风格字符串完成 #include <iostream> #include<array>using namespace std;int main() {int a0,A0,num0,space0,other0;array<char…

中国大模型迎来“95后” 百度奖学金发掘百位“未来AI技术领袖”

在人工智能掀起的科技革命和产业变革浪潮下&#xff0c;大模型成为最受关注的研究领域。1月22日&#xff0c;第十一届百度奖学金颁奖典礼在北京举行&#xff0c;来自全球顶尖高校及科研机构的10位“未来AI技术领袖”脱颖而出&#xff0c;他们平均年龄仅27岁&#xff0c;其中8人…

Oracle触发器简单应用示例

目录 一、应用描述 【1】、应用场景&#xff1a; 【2】、具体场景&#xff1a; 二、表结构介绍 【1】表名介绍&#xff1a; 【2】表结构&#xff1a; 三、设置触发器 一、应用描述 【1】、应用场景&#xff1a; 现有一张库存明细以及销售明细表&#xff0c;销售明细表发生…

python合并多个dict---合并多个字典值---字典值相加

文章目录 序多个dict同key值相加collection.Counter传参重载号 多个dict合并练习 序 主要是借助Counter、函数传参和运算符重载&#xff01;各有优劣&#xff01; 多个dict同key值相加 collection.Counter 借助collections.Counter&#xff0c;但是它只适用于值为整数或者小…

扭蛋机小程序开发,让扭蛋迷体验到扭蛋的趣味性

扭蛋机作为盲盒的前身&#xff0c;也是深受大众的欢迎&#xff0c;十几到几十不等的价格就可以让消费者体验到幸福感。扭蛋机具有价格低、性价比高的特点&#xff0c;扭蛋中的主题商品也都是经典热门动漫&#xff0c;具有较高的收藏价值&#xff0c;吸引了不少的扭蛋迷。 随着…