https://zhuanlan.zhihu.com/p/60380557

子查询,分两种情况,

对于在From中的,称为‘derived table’,这种场景比较简单

对于在select,where中的,scalar表达式,这是主要要考虑的对象,因为这种情况cross了relational和scalar的处理

子查询,最关键的区分,是关联子查询(Correlated Subquery)和非关联子查询(Non-correlated Subquery)

关联子查询,子查询的执行,子查询参数,依赖于外层父查询输出的属性

非关联子查询,子查询的执行,不依赖于外层父查询的任何属性值,这样子查询具有独立性,可独自求解

非关联子查询的优化非常简单,因为可以独立求解,那就先求出并物化,带入父查询join即可

所以子查询优化的核心就是,去关联,de-correlate

从子查询返回的数据分类,

标量(Scalar-valued)子查询: 输出就是一个标量
存在性检测(Existential Test)子查询:特指 EXISTS 的子查询,返回一个布尔值
集合比较(Quantified Comparision)子查询:特指 IN、SOME、ANY 的查询,返回一个布尔值或Null,可能返回null

先看几篇基础的论文,

Microsoft的论文,

Parameterized Queries and Nesting Equivalencies - C Galindo-Legaria
Orthogonal Optimization of Subqueries and Aggregation - C Galindo-Legaria, M Joshi
Execution Strategies for SQL Subqueries - Mostafa Elhemali

Parameterized Queries and Nesting Equivalencies

这篇论文核心,是提出Apply算子,并且如何通过各种规则,把Apply算子转换为普通的join

例子中一个,标量子查询的例子,

对于关联子查询,语义其实就是,对于outer表的每一行数据,都执行一遍子查询,这个非常类似,function programming里面的Apply算子

所以这里就是是用Apply算子来,描述这种关联性

Apply算子的定义,

对于关系表R,其中每个r,带入E,因为E是个参数化expression,把结果求并集

这里其实对于R是要求Distinct,因为R中的r可能会重复,所以一般会加上一个算子去重

中间的A❌就代表apply算子,这里和普通join一样,根据对于E返回的Empty的处理,分为,

看上面的例子,用Apply算子的结果,

如果outer表足够小,并且有比较好的indexes的情况下,Correlatied执行效率也很好的

但是大多数一般情况下,Apply执行明显效率很低,所以要基于Apply算子去进行优化,Apply算子是个中间状态,比原来的形式更加容易使用关系代数优化

Apply的优化就,SubQuery unnesting或correlation removel,就是把Apply算子转换为regular join的过程,

下面看个最直接的例子,

Orthogonal Optimization of Subqueries and Aggregation

先看个例子,

标量,关联子查询的例子

最直接的方法,直接Correlated execution,不一定低效,如果Outer表很小,并且有适当的索引

80年代,提出过一些优化的方案,

比如,先Outerjoin,再aggregate的方案

或者,先Aggregate,再Join

但是这些方案,不是系统的方法论,不同的情况下,需要分析并使用不同的方法,

本文的方式是,把这些方法分解成,orthogonal, reusable primitives,用的时候可以组合起来,用cost-estimation的方式,评估到底使用哪些primitives

可以看出,分为图中的几步,下面分别解释一下各个步骤,

Algebrize

用Apply算子来抽象和替换parameterized execution of subexpressions

Apply算子的好处在于,去除relation和scalar节点间的mutual recursion

例子,左图,查询中有,scalar表达式,scalar表达式中又有子查询,所以执行的时候,需要反复在查询计划执行器和表达式执行器之间不断切换,效率很低,而且隔着scalar表达式,没法用关系代数进行优化或reorder

所以用Apply算子变换到右图,把子查询从scalar表达式中remove掉,放到关系代数树中

这里用标量子查询为例,但是其他的子查询也是一样的

这步只是对过程做了抽象,但实际上并没有改变执行计划

这里还提到一种,SegmentApply算子

可以认为是batch版本的Apply算子

因为我们可以用column A对R进行分组,对于每一组,table-valued,去调用E

a就是Distinct(A)

Remove Correlation

也就是remove apply

做法, 不断下推Apply,直到不关联了,转化为regular join

The process consists of pushing down Apply in the operator tree, towards the leaves, until the right child of Apply is no longer parameterized off the left child.

可以使用的转换rules,

(1) (2),左右不相干的情况下,apply可以直接转化成join

后面所有rules的目的,就是要转换成满足 (1) (2)

这里,(8)(9),比较难理解

首先,先看两个概念,

Vector Aggregation,GroupBY聚合,group by A,aggregate with Function F
关键,表为空的时候,返回也是empty

Scalar Aggregation,全局聚合,不指定A,aggregate with Function F
关键,总会有一行返回值,不会为empty;并且返回值和Aggregate函数相关,如果是sum,返回null,如果是count,返回0

(8)中,columns(R)表示join key,把group by提到外面后,需要先按照join key做group by

(8)和(9)的差别就是,(9)是Scalar Aggregation,所以返回值对于empty会出现null,所以F’需要特殊处理,用非null的column
再者Scalar Aggre提到外面后变成Vector Aggre (group by join key)

下面看个例子,仍然是上面的SQL

首先,为什么是Scalar Aggre,因为这里Group by join key,对于Apply算子,group by每次只apply到一个customer,所以是Scalar Aggre
用(9),把Scalar Aggre提出来,变成Vector Aggre
提出GroupBY后,剩下的可以直接应用(2)消除Apply
最后,由于最终的aggre结果需要非null,所以可以简化成inner join

Reorder Groupby

Groupby可以和其他算子进行交换,比如filter,join等

GroupBy的Reorder是否会降低cost,这个需要cost model去判断,比如先GroupBY,后Join,还是先Join,后GroupBy

GroupBy和Filter Reorder

条件,if and only if all the columns used in the filter are functionally determined by the grouping columns in the input relation

过滤的columns,由GroupBy columns决定

GroupBy和Join Reorder

GroupBy pushdown 条件,

GroupBy Pullup的条件,

Segmented Execution

以TPCH-17为例,

完成去关联后的计划如下,

这个计划的问题是,我们其实不用对所有Lineitem的rows都做这样的聚合过滤,其实只是需要对过滤后的PartKey对应的lineitem做

所以这里的方法是,把LineItem按照partkey进行group,每个group叫做Segment,然后对Segment执行子查询

叫做SegmentApply,

对于SegmentApply,下面要做的是,按照Part的条件过滤Segments,也就是要把外部的条件Push down到SegmentApply里面,

push down的条件是,segment的完整性,join的条件以segment为条件进行过滤,而不会过滤掉部分row

完成pushdown的结果如下,在SegmentApply之前,先会对LineItem做join进行过滤掉不需要的segment

SubQuery优化的更多相关文章

  1. 【MySQL】优化—工欲善其事,必先利其器之EXPLAIN

    接触MySQL已经有一段时间了,了解如何优化它也迫在眉睫了,话说工欲善其事,必先利其器.最近我就打算了解下几个优化MySQL中经常用到的工具.今天就简单介绍下EXPLAIN. 环境准备 Explain ...

  2. MySQL优化—工欲善其事,必先利其器之EXPLAIN(转)

    最近慢慢接触MySQL,了解如何优化它也迫在眉睫了,话说工欲善其事,必先利其器.最近我就打算了解下几个优化MySQL中经常用到的工具.今天就简单介绍下EXPLAIN. 内容导航 id select_t ...

  3. MySQL优化—工欲善其事,必先利其器之EXPLAIN

    最近慢慢接触MySQL,了解如何优化它也迫在眉睫了,话说工欲善其事,必先利其器.最近我就打算了解下几个优化MySQL中经常用到的工具.今天就简单介绍下EXPLAIN. 内容导航 id select_t ...

  4. MySQL使用现状分析与优化

    前言 再紧张的裁员氛围,也不该影响你学习的心态.不要本末倒置,技术永远不会落后,只要你还在学习的道路上,没有后退. 数据库架构 目前生产环境RDS是多区可用架构.数据库实例发生计划内或计划外的中断时, ...

  5. mysql之explain

    ⊙ 使用EXPLAIN语法检查查询执行计划   ◎ 查看索引的使用情况   ◎ 查看行扫描情况   ⊙ 避免使用SELECT *   ◎ 这会导致表的全扫描   ◎ 网络带宽会被浪费   话说工欲善其 ...

  6. [慢查优化]慎用MySQL子查询,尤其是看到DEPENDENT SUBQUERY标记时

    案例梳理时间:2013-9-25 写在前面的话: 在慢查优化1和2里都反复强调过 explain 的重要性,但有时候肉眼看不出 explain 结果如何指导优化,这时候还需要有一些其他基础知识的佐助, ...

  7. 深入理解MySql子查询IN的执行和优化

    IN为什么慢? 在应用程序中使用子查询后,SQL语句的查询性能变得非常糟糕.例如: SELECT driver_id FROM driver where driver_id in (SELECT dr ...

  8. 我的MYSQL学习心得(十六) 优化

    我的MYSQL学习心得(十六) 优化 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据 ...

  9. Mysql性能优化一

    下一篇:Mysql性能优化二 mysql的性能优化无法一蹴而就,必须一步一步慢慢来,从各个方面进行优化,最终性能就会有大的提升. Mysql数据库的优化技术 对mysql优化是一个综合性的技术,主要包 ...

随机推荐

  1. 继续了解Java的纤程库 – Quasar

    前一篇文章Java中的纤程库 – Quasar中我做了简单的介绍,现在进一步介绍这个纤程库. Quasar还没有得到广泛的应用,搜寻整个github也就pinterest/quasar-thrift这 ...

  2. 推荐一个去除图片人物背景的工具Removebg

    可以在线使用,url:https://www.remove.bg/users/sign_in 用邮箱免注册一个免费账号: 注册的邮箱会收到一封激活账号的邮件: 点击Activate account后激 ...

  3. React: webpack模块组织关系

    现代前端开发离不开打包工具,以 webpack 为代表的打包工具已经成为日常开发必备之利器,拿 React 技术栈为例,我们 ES6 形式的源代码,需要经过 webpack 和 Babel 处理,才能 ...

  4. 使用SSH配置git服务器免密提交

    1. 生成SSH 1.1下载 下载工具 puttygen.exe ,当然其他工具请自行搜索. 下载地址: 下载地址1   百度网盘 (提取码: if8g)https://pan.baidu.com/s ...

  5. k8s之Configmap与Secret

    ConfigMap:k8s标准资源,将配置文件做成k8s资源,使其它资源可加载其中配置 Secret:实现加密功能的安全配置文件.由多个key:val中组成 创建configmap资源,可直接使用ku ...

  6. 在CentOS 7上修改主机名的方法

    这次我们来讲解一下如何在CentOS 7环境上修改主机名 1.从VMware上登录CentOS 7的虚拟机,并以root用户登录. 2.查看未修改前的主机名 1>.我们可以通过文件hostnam ...

  7. FreeBSD安装后使用su命令显示sorry的解决办法

    FreeBSD中,可以使用su命令成为root用户,但FreeBSD对执行su命令的用户进行了更严格的限制,能使用su命令的用户必须属于wheel组(root的基本属组,组ID为0),否则就不能通过 ...

  8. UART 串口示例代码

    /* uart_tx.c */ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #i ...

  9. 算法- 求解最大平均值的子树-经典dfs题目

    给一棵二叉树,找到有最大平均值的子树.返回子树的根结点. Example 样例1 输入: {1,-5,11,1,2,4,-2} 输出:11 说明: 这棵树如下所示: 1 / \ -5 11 / \ / ...

  10. Echo团队Alpha冲刺随笔 - 第八天

    项目冲刺情况 进展 程序基本完成,根据实际,添加完善新接口 问题 根据功能对接出现的问题继续进行改进 心得 放假了放松下 今日会议内容 黄少勇 今日进展 测试小程序,添加异常和错误操作的处理 存在问题 ...