当前位置: 首页 > news >正文

Postgresql源码(116)提升子查询案例分析

0 总结

对于SQL:select * from student, (select * from score where sno > 2) s where student.sno = s.sno;

pullup在pull_up_subqueries函数内递归完成,分几步:

  1. 将内层rte score追加到上层rtbable中:rte1是student、rte2带subquery是子查询、rte3是score。
  2. 调整所有var的varno(从1指向3)、varlevelsup(本例不涉及);还有其他调整本例不涉及。
  3. 将上层代表子查询的rte2的subquery清空,但rte2不删除。
  4. 将上层jointree中,指向子查询的rte替换为 子查询中的FromExpr(sno > 2)。

在这里插入图片描述

1 待分析场景

drop table student;
create table student(sno int, sname varchar(10), ssex int);
insert into student values(1, 'stu1', 0);
insert into student values(2, 'stu2', 1);
insert into student values(3, 'stu3', 1);
insert into student values(4, 'stu4', 0);drop table course;
create table course(cno int, cname varchar(10), tno int);
insert into course values(10, 'meth', 1);
insert into course values(11, 'english', 2);drop table teacher;
create table teacher(tno int, tname varchar(10), tsex int);
insert into teacher values(1, 'te1', 1);
insert into teacher values(2, 'te2', 0);drop table score;
create table score (sno int, cno int, degree int);
insert into score values (1, 10, 100);
insert into score values (1, 11, 89);
insert into score values (2, 10, 99);
insert into score values (2, 11, 90);
insert into score values (3, 10, 87);
insert into score values (3, 11, 20);
insert into score values (4, 10, 60);
insert into score values (4, 11, 70);

带子查询的语句:select * from student, (select * from score where sno > 2) s where student.sno = s.sno;

set enable_hashjoin to off;
set enable_mergejoin to off;explain select * from student, (select * from score where sno > 2) s where student.sno = s.sno;QUERY PLAN
---------------------------------------------------------------------Nested Loop  (cost=0.00..11278.20 rows=3740 width=58)Join Filter: (student.sno = score.sno)->  Seq Scan on student  (cost=0.00..21.00 rows=1100 width=46)->  Materialize  (cost=0.00..38.90 rows=680 width=12)->  Seq Scan on score  (cost=0.00..35.50 rows=680 width=12)Filter: (sno > 2)||||||||||
||等价写法||
vvvvvvvvvvvexplain select * from student, score where score.sno > 2 and student.sno = score.sno;QUERY PLAN
---------------------------------------------------------------------Nested Loop  (cost=0.00..11278.20 rows=3740 width=58)Join Filter: (student.sno = score.sno)->  Seq Scan on student  (cost=0.00..21.00 rows=1100 width=46)->  Materialize  (cost=0.00..38.90 rows=680 width=12)->  Seq Scan on score  (cost=0.00..35.50 rows=680 width=12)Filter: (sno > 2)

pull_up_subqueries做的事情就是帮我们把子查询上拉了,下面分析上拉是如何做的。

select * from student, (select * from score where sno > 2) s where student.sno = s.sno;


Plannerinfo完整结构
在这里插入图片描述

注意pull_up_subqueries只对jointree做处理。

void
pull_up_subqueries(PlannerInfo *root)
{/* Top level of jointree must always be a FromExpr */Assert(IsA(root->parse->jointree, FromExpr));/* Recursion starts with no containing join nor appendrel */root->parse->jointree = (FromExpr *)pull_up_subqueries_recurse(root, (Node *) root->parse->jointree,NULL, NULL);/* We should still have a FromExpr */Assert(IsA(root->parse->jointree, FromExpr));
}

2 pull_up_subqueries流程分析

2.1 处理FromExpr下面挂的第一个RANGETBLREF(student表)

FromExpr的第一张表是student表,指向一个rtekind = RTE_RELATION普通表类型,无需做任何处理。
在这里插入图片描述

2.2 处理FromExpr下面挂的第二个RANGETBLREF(子查询)

FromExpr的第二个rte是子查询(select * from score where sno > 2) s,可以看到引用的rte结构的subquery指向了内层query:
在这里插入图片描述
开始进入pull_up_simple_subquery内部处理,进入路径:
在这里插入图片描述
在分析pull_up_simple_subquery前有两个准入条件:

  1. rte->rtekind == RTE_SUBQUERY
  2. is_simple_subquery:不全部列举了,其中重要的是子查询不能带有一些特殊的语法:
is_simple_subquery...if (subquery->hasAggs ||subquery->hasWindowFuncs ||subquery->hasTargetSRFs ||subquery->groupClause ||subquery->groupingSets ||subquery->havingQual ||subquery->sortClause ||subquery->distinctClause ||subquery->limitOffset ||subquery->limitCount ||subquery->hasForUpdate ||subquery->cteList)return false;...

2.3 进入pull_up_simple_subquery开始处理子查上拉

第一步:拿到rte指向的子查询的Query树,构造PlannerInfo开始处理。

static Node *
pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte,JoinExpr *lowest_outer_join,AppendRelInfo *containing_appendrel)
{Query	   *subquery;Query	   *parse = root->parse;PlannerInfo *subroot;subquery = copyObject(rte->subquery);subroot = makeNode(PlannerInfo);subroot->parse = subquery;......

第二步:递归的处理sublink、subquery等。

	replace_empty_jointree(subquery);if (subquery->hasSubLinks)pull_up_sublinks(subroot);preprocess_function_rtes(subroot);pull_up_subqueries(subroot);

第三步:开始pull up

到这里subroot就是rte2的subquery子查询的结构还没有任何调整:
在这里插入图片描述

	/** Adjust level-0 varnos in subquery so that we can append its rangetable* to upper query's.  We have to fix the subquery's append_rel_list as* well.*/rtoffset = list_length(parse->rtable);  // 2OffsetVarNodes((Node *) subquery, rtoffset, 0);OffsetVarNodes((Node *) subroot->append_rel_list, rtoffset, 0);

parse是上层查询的,上层有两个rtable。因为要把子查询拉平,所以把子查询的varno的指向调整一下,因为是要append到父查询,所以直接加上父查询rte的个数就好了(这里是2)。加完了应该指向父查询rte的3的位置(现在父查询只有两个rte,3位置是空的)。

OffsetVarNodes((Node *) subquery, 2, 0);

  1. 调整var→varno:1→3。
  2. 调整rangetblref→rindex:1→3。
    在这里插入图片描述
	/** Upper-level vars in subquery are now one level closer to their parent* than before.*/IncrementVarSublevelsUp((Node *) subquery, -1, 1);IncrementVarSublevelsUp((Node *) subroot->append_rel_list, -1, 1);
  • 这一步调整的目的:因为varlevelsup=1表示引用上一层的列(相当于距离)这里拉平后,varlevelsup就需要-1了,因为距离少了1。
  • 在当前SQL中select * from student, (select * from score where sno > 2) s where student.sno = s.sno;,开始调整var→varlevelsup字段,注意这个字段表示当前查询中使用了上层的变量,但上面子查询中(select * from score where sno > 2)没有引用上层的任何列,所以子查询中的var→varlevelsup都是0。这一步调整不会有影响。
	/** Now append the adjusted rtable entries and their perminfos to upper* query. (We hold off until after fixing the upper rtable entries; no* point in running that code on the subquery ones too.)*/CombineRangeTables(&parse->rtable, &parse->rteperminfos,subquery->rtable, subquery->rteperminfos);

开始把子查询的RTE拷贝到上层,现在子查询里面的varno=3指向就对了。
在这里插入图片描述

	/** We no longer need the RTE's copy of the subquery's query tree.  Getting* rid of it saves nothing in particular so far as this level of query is* concerned; but if this query level is in turn pulled up into a parent,* we'd waste cycles copying the now-unused query tree.*/rte->subquery = NULL;

删除子查询RTE带的Query,注意现在还缺一个条件。
在这里插入图片描述

pull_up_simple_subqueryreturn (Node *) subquery->jointree;

返回一个jointree带着条件。
在这里插入图片描述
返回去后,在这里把fromlist指向的第二个rte(子查询)换成 上面计算好的jointree。

然后就拉平了。

pull_up_subqueries_recurse...else if (IsA(jtnode, FromExpr)){FromExpr   *f = (FromExpr *) jtnode;ListCell   *l;Assert(containing_appendrel == NULL);/* Recursively transform all the child nodes */foreach(l, f->fromlist){lfirst(l) = pull_up_subqueries_recurse(root, lfirst(l),lowest_outer_join,NULL);}}

最终效果对比

pullup前 vs pullup后
在这里插入图片描述

相关文章:

Postgresql源码(116)提升子查询案例分析

0 总结 对于SQL:select * from student, (select * from score where sno > 2) s where student.sno s.sno; pullup在pull_up_subqueries函数内递归完成,分几步: 将内层rte score追加到上层rtbable中:rte1是student、rte2带…...

CNP实现应用CD部署

上一篇整体介绍了cnp的功能,这篇重点介绍下CNP产品应用开发的功能。 简介 CNP的应用开发,主要是指的应用CD部署的配置管理。 应用列表,用来创建一个应用,一般与项目对应,也可以多个应用对应到一个项目。具体很灵活。…...

kubeadm join 192.168.10.16:6443 --token xxx报错Failed to request cluster-info

1、node节点执行 kubeadm join 192.168.10.16:6443 --token hak4zi.hrib9uv4p62t1uok --discovery-token-ca-cert-hash sha256:4337638eef783ee6a66045ad699722079e071c2dfbaa21e37d3174f04d58ea97 --v2 报错 [discovery] Failed to request cluster-info, will try again: G…...

车载以太网-传输层-TCP

文章目录 TCP协议TCP协议报文格式TCP报文的示例TCP建立连接TCP断开连接TCP协议测试TCP协议 车载以太网TCP协议是一种在车载以太网网络中使用的传输控制协议(TCP)。它是一种面向连接的协议,用于在车辆之间或车辆与基础设施之间传输数据。TCP协议提供了可靠的数据传输,确保数…...

java:简单入门定时任务的几种方式Timer、Quartz、Spring Task

背景 后端的定时任务在许多应用中都扮演着重要的角色,它们可用于处理重复性任务、执行定期操作或处理需要定时触发的任务。以下是一些使用场景的示例: 数据同步:在分布式系统中,不同系统之间经常需要进行数据同步。例如&#xf…...

木子-前端-方法标签属性小记(普通jsp/html篇)2023~2024

目录 1、如何在前端页面将base转成存进input的图片格式 2、通过前端页面判断当前使用方式PC端还是手机端的极简易方法 1、如何在前端页面将base转成存进input的图片格式 不是直接存进input里,只是将文件转成对应的格式。 data.picPath是base64编码,我…...

音视频项目—基于FFmpeg和SDL的音视频播放器解析(十七)

介绍 在本系列,我打算花大篇幅讲解我的 gitee 项目音视频播放器,在这个项目,您可以学到音视频解封装,解码,SDL渲染相关的知识。您对源代码感兴趣的话,请查看基于FFmpeg和SDL的音视频播放器 如果您不理解本…...

使用netty实现WebSocket协议通信

服务器与浏览器之间实现通信,一般都是由浏览器发起http请求,服务端对http请求进行响应,要实现服务端主动向浏览器推送数据,一般采用的方案都是websocket主动推送,或者前端实现轮询方式拉取数据,轮询方式多少…...

uniapp开发小程序,包过大解决方案

1、首先和大家说一下 微信小程序 主包限制不能超过2M 分包一共不能超过8M 然后具体解决优化步骤如下, 将主包进行分包 在pages.json 下subPackages里面进行配置分包 分包配置完 配置过的文件都需要进行修改对应的路径 2 、 在运行的时候 一定要勾选 压缩代码 有…...

Go语言中string与byte转换

简介 string与byte的转换是最常见的一种,通常我们会使用强转方式,但其实还有另一种更加高效的方式,本文会演示两种转换方式。 普通转换 func main() {fmt.Println([]byte("abcd"))fmt.Println(string([]byte{1, 2, 3})) }输出 […...

机器学习8:在病马数据集上进行算法比较(ROC曲线与AUC)

ROC曲线与AUC。使用不同的迭代次数(基模型数量)进行 Adaboost 模型训练,并记录每个模型的真阳性率和假阳性率,并绘制每个模型对应的 ROC 曲线,比较模型性能,输出 AUC 值最高的模型的迭代次数和 ROC 曲线。 …...

70. 爬楼梯 --力扣 --JAVA

题目 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢? 解题思路 通过对爬楼梯进行分解,爬到当前台阶的方式分为两种,即由上一个台阶通过爬1和上两个台阶爬2,同公…...

体感互动游戏VR游戏AR体感游戏软件开发

随着科技的不断发展,体感互动游戏正逐渐成为游戏行业的一个重要趋势。这类游戏通过利用传感器、摄像头和运动控制器等技术,使玩家能够通过身体动作与游戏进行实时互动,极大地提升了娱乐体验。 1. 游戏设计与互动元素 体感互动游戏的核心在于…...

计算3个点的6种分布在平面上的占比

假设平面的尺寸是6*6,用11的方式构造2,在用21的方式构造3 2 2 2 1 2 2 2 2 2 1 2 2 2 2 2 1 2 2 3 3 3 x 3 3 2 2 2 1 2 2 2 2 2 1 2 2 在平面上有一个点x,11的操作吧平面分成了3部分2a1,2a…...

【香橙派】实战记录1——简介及烧录 Linux 镜像

文章目录 一、简介1、参数2、结构3、其他配件4、下载资料 二、基于 Windows PC 将 Linux 镜像烧写到 TF 卡的方法1、使用 balenaEtcher 烧录 Linux 镜像的方法2、效果 一、简介 Orange Pi Zero 3 香橙派是一款开源的单板卡片电脑, 新一代的arm64开发板,…...

redis之高可用

(一)redis之高可用 1、在集群当中有一个非常重要的指标,提供正常服务的时间的百分比(365天)99.9% 2、redis的高可用的含义更加广泛,正常服务是指标之一,数据容量的扩展、数据的安全性 3、在r…...

使用 Core Tools 在本地开发 Azure Functions

学习模块 使用 Core Tools 在本地创建和运行 Azure Functions - Training | Microsoft Learn 文档 使用 Core Tools 在本地开发 Azure Functions | Microsoft Learn GitHub - Azure/azure-functions-core-tools: Command line tools for Azure Functions 其它 安装适用于 A…...

Java零基础——Spring篇

1.Spring框架的介绍 1.1 传统的项目的架构 在传统的项目中,一般遵循MVC开发模型。 (1) view层与用户进行交互,显示数据或者将数据传输给view层。 (2) 在controller层创建service层对象,调用service层中业务方法。 (3) 在service层创建dao…...

jenkins清理缓存命令

def jobName "yi-cloud-operation" //删除的项目名称 def maxNumber 300 // 保留的最小编号&#xff0c;意味着小于该编号的构建都将被删除 Jenkins.instance.getItemByFullName(jobName).builds.findAll { it.number < maxNumber }.each { it.delet…...

什么是深度学习

一、深度学习的发展历程 1.1 Turing Testing (图灵测试) 图灵测试是人工智能是否真正能够成功的一个标准&#xff0c;“计算机科学之父”、“人工智能之父”英国数学家图灵在1950年的论文《机器会思考吗》中提出了图灵测试的概念。即把一个人和一台计算机分别放在两个隔离的房…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…...

【Linux】shell脚本忽略错误继续执行

在 shell 脚本中&#xff0c;可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行&#xff0c;可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令&#xff0c;并忽略错误 rm somefile…...

day52 ResNet18 CBAM

在深度学习的旅程中&#xff0c;我们不断探索如何提升模型的性能。今天&#xff0c;我将分享我在 ResNet18 模型中插入 CBAM&#xff08;Convolutional Block Attention Module&#xff09;模块&#xff0c;并采用分阶段微调策略的实践过程。通过这个过程&#xff0c;我不仅提升…...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂

蛋白质结合剂&#xff08;如抗体、抑制肽&#xff09;在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上&#xff0c;高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术&#xff0c;但这类方法普遍面临资源消耗巨大、研发周期冗长…...

FastAPI 教程:从入门到实践

FastAPI 是一个现代、快速&#xff08;高性能&#xff09;的 Web 框架&#xff0c;用于构建 API&#xff0c;支持 Python 3.6。它基于标准 Python 类型提示&#xff0c;易于学习且功能强大。以下是一个完整的 FastAPI 入门教程&#xff0c;涵盖从环境搭建到创建并运行一个简单的…...

渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止

<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet&#xff1a; https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序

一、开发环境准备 ​​工具安装​​&#xff1a; 下载安装DevEco Studio 4.0&#xff08;支持HarmonyOS 5&#xff09;配置HarmonyOS SDK 5.0确保Node.js版本≥14 ​​项目初始化​​&#xff1a; ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...

安卓基础(aar)

重新设置java21的环境&#xff0c;临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的&#xff1a; MyApp/ ├── app/ …...

招商蛇口 | 执笔CID,启幕低密生活新境

作为中国城市生长的力量&#xff0c;招商蛇口以“美好生活承载者”为使命&#xff0c;深耕全球111座城市&#xff0c;以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子&#xff0c;招商蛇口始终与城市发展同频共振&#xff0c;以建筑诠释对土地与生活的…...

C#中的CLR属性、依赖属性与附加属性

CLR属性的主要特征 封装性&#xff1a; 隐藏字段的实现细节 提供对字段的受控访问 访问控制&#xff1a; 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性&#xff1a; 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑&#xff1a; 可以…...