Postgresql源码(104)子连接提升过程pull_up_sublinks

news2024/11/26 1:52:25

1 场景构造

drop table student;
create table student(sno int primary key, 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 primary key, 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 primary key, 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);

case1

SELECT * FROM STUDENT a WHERE a.sno > ANY (SELECT b.sno from STUDENT b); 
 sno | sname | ssex 
-----+-------+------
   2 | stu2  |    1
   3 | stu3  |    1
   4 | stu4  |    0

explain SELECT * FROM STUDENT a WHERE a.sno > ANY (SELECT b.sno from STUDENT b); 
                                        QUERY PLAN                                         
-------------------------------------------------------------------------------------------
 Nested Loop Semi Join  (cost=0.15..208.42 rows=367 width=46)
   ->  Seq Scan on student a  (cost=0.00..21.00 rows=1100 width=46)
   ->  Index Only Scan using student_pkey on student b  (cost=0.15..6.62 rows=367 width=4)
         Index Cond: (sno < a.sno)

首先从逻辑上分析这条SQL是可以做子连接提升的,因为子连接中的结果sno和外部表达式判断的sno是同一字段,这样a表可以作为半连接的外表,b表作为内表,利用半连接的特性,一旦内表找到一条连接终止。这样就实现了any的语义,也没有生成subplan,提升了性能。

下面是一个反例:

这里的子连接无法提升,因为子连接的结果集cno和外部判断条件ssex没有关系,只能生成subplan拿到所有结果后返回给上层,这种执行计划效率明显是不如上面case。

case2

explain SELECT * FROM student WHERE ssex < ANY (SELECT cno FROM score WHERE student.sno = student.sno);  
                              QUERY PLAN                               
-----------------------------------------------------------------------
 Seq Scan on student  (cost=0.00..19551.50 rows=550 width=46)
   Filter: (SubPlan 1)
   SubPlan 1
     ->  Result  (cost=0.00..30.40 rows=2040 width=4)
           One-Time Filter: (student.sno = student.sno)
           ->  Seq Scan on score  (cost=0.00..30.40 rows=2040 width=4)

2 代码分析

下面以explain SELECT * FROM STUDENT a WHERE a.sno > ANY (SELECT b.sno from STUDENT b); 为例,尝试分析这条SQL是如何做逻辑优化的。

2.1 打印Query结构

p elog_node_display(LOG, "parse tree", root->parse, true)

日志中获取

2023-05-29 11:32:51.634 CST,"mingjie","postgres",14113,"[local]",647408f7.3721,7,"EXPLAIN",2023-05-29 10:07:51 CST,3/59095,0,LOG,00000,"parse tree:","   {QUERY 
   :commandType 1 
   :querySource 0 
   :canSetTag true 
   :utilityStmt <> 
   :resultRelation 0 
   ...
   ...

导入pgNodeGraph工具,生成结果:
在这里插入图片描述

2.2 pull_up_sublinks_jointree_recurse

recurse第一层:pull_up_sublinks_jointree_recurse

pull_up_sublinks_jointree_recurse
	else if (IsA(jtnode, FromExpr))
		FromExpr   *f = (FromExpr *) jtnode;
		foreach(l, f->fromlist)
			newchild = pull_up_sublinks_jointree_recurse(root, lfirst(l), &childrelids);

在这里插入图片描述

recurse第二层:pull_up_sublinks_jointree_recurse

pull_up_sublinks_jointree_recurse
	else if (IsA(jtnode, RangeTblRef))
		// varno == 1
		int                     varno = ((RangeTblRef *) jtnode)->rtindex;
		*relids = bms_make_singleton(varno);

在这里插入图片描述

recurse退回第一层:pull_up_sublinks_jointree_recurse

else if (IsA(jtnode, FromExpr))
	foreach(l, f->fromlist)
		pull_up_sublinks_jointree_recurse  // 执行结束
	...
	newf->quals = pull_up_sublinks_qual_recurse(root, f->quals,
													&jtlink, frelids,
													NULL, NULL);

传入SUBLINK
在这里插入图片描述

recurse进入pull_up_sublinks_qual_recurse→convert_ANY_sublink_to_join处理quals

收到SUBLINK

第一步:contain_vars_of_level检查子连接里面有没有引用父Query的var,如果没有可以继续,walker函数为contain_vars_of_level_walker,只检查Var、CurrentOfExpr、PlaceHolderVar;如果发现还有子Query,把context记录的sublevels_up++(一开始是0)后,在进去递归子Query;因为该逻辑只是检查有没有相邻的上层引用,跨层不管。

pull_up_sublinks_qual_recurse
	if (IsA(node, SubLink))
		convert_ANY_sublink_to_join
			if (contain_vars_of_level((Node *) subselect, 1))
				return NULL;
			...
			...

contain_vars_of_level函数调用walker宏遍历sublink树。

bool
contain_vars_of_level(Node *node, int levelsup)
{
	int			sublevels_up = levelsup;
	return query_or_expression_tree_walker(node,
										   contain_vars_of_level_walker,
										   (void *) &sublevels_up,
										   0);
}

在这里插入图片描述

第二步:pull_varnos检查子连接的test表达式必须包含父查询的var,否则也没办法改成join。

pull_up_sublinks_qual_recurse
	if (IsA(node, SubLink))
		convert_ANY_sublink_to_join
			if (contain_vars_of_level((Node *) subselect, 1))
				return NULL;
			...
			...
			upper_varnos = pull_varnos(root, sublink->testexpr); 
			if (bms_is_empty(upper_varnos))
				return NULL;                                

pull_varnos函数

Relids
pull_varnos(PlannerInfo *root, Node *node)
{
	pull_varnos_context context;
	context.varnos = NULL;
	context.root = root;
	context.sublevels_up = 0;
	query_or_expression_tree_walker(node,
									pull_varnos_walker,
									(void *) &context,
									0);
	return context.varnos;
}

遍历完成后,记录了一个varno==1到upper_varnos中。
在这里插入图片描述

第三步:convert_ANY_sublink_to_join构造新的join结构

{JOINEXPR 
   :jointype 4 
   :isNatural false 
   :larg <> 
   :rarg 
      {RANGETBLREF 
      :rtindex 2
      }
   :usingClause <> 
   :join_using_alias <> 
   :quals 
      {OPEXPR 
      :opno 521 
      :opfuncid 147 
      :opresulttype 16 
      :opretset false 
      :opcollid 0 
      :inputcollid 0 
      :args (
         {VAR 
         :varno 1 
         :varattno 1 
         :vartype 23 
         :vartypmod -1 
         :varcollid 0 
         :varnullingrels (b)
         :varlevelsup 0 
         :varnosyn 1 
         :varattnosyn 1 
         :location 38
         }
         {VAR 
         :varno 2 
         :varattno 1 
         :vartype 23 
         :vartypmod -1 
         :varcollid 0 
         :varnullingrels (b)
         :varlevelsup 0 
         :varnosyn 2 
         :varattnosyn 1 
         :location -1
         }
      )
      :location 44
      }
   :alias <> 
   :rtindex 0
   }

convert_ANY_sublink_to_join返回JoinExpr结构
在这里插入图片描述

第四步:pull_up_sublinks_qual_recurse继续补完JoinExpr结构

2.3 pull_up_sublinks返回新的jointree

在这里插入图片描述

2.4 (逻辑解析最后形态)pull_up_subqueries子查询合并到rangetblentry

在这里插入图片描述

2.5 grouping_planner后

在这里插入图片描述

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

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

相关文章

模块化

一、目标 能够说出模块化的好处能够知道CommonJS规定了哪些内容能够说出Node.js中模块的三大分类各自是什么能够使用npm管理包能够了解什么是规范的包结构能够了解模块的加载机制 二、目录 模块化的基本概念Node.js中模块的分类npm与包模块的加载机制 1.模块化的基本概念 …

spring源码解读

深入了解Spring Bean Java bean和spring bean区别 Java bean的属性私有&#xff0c;只能通过get和set方法来对属性进行操作。Spring bean是由spring容器生成和管理的对象。 spring Bean的定义方式 xml文件 。 声明式。 bean注解。 声明式。 component注解。声明式。 Bea…

房产中介APP开发功能有哪些?

房产中介APP开发功能有哪些&#xff1f; 1. 发布信息。中介或房东通过房地产中介APP客户端发布出租房屋的相关信息。 2. 房屋搜查。根据不同类型的房源进行分类&#xff0c;如公寓、整租、合租、写字楼、办公楼等&#xff0c;也可以根据不同的位置信息、商圈、距…

2023年下半年软考高级需要报班吗?

首先&#xff0c;对于软考高级考试报班与否的问题&#xff0c;需要根据自身的情况来做出决定。如果你有较强的自学能力&#xff0c;且具备丰富的实际工作经验和技术知识&#xff0c;那么不报班也完全可以自学备考。但如果你对软件工程的知识掌握程度较低&#xff0c;或者时间紧…

算法01-算法概念与描述

文章目录 总结大纲要求算法概念举个例子&#xff1a;量水问题 算法描述算法的时间复杂度 总结 本系列为C算法学习系列&#xff0c;会介绍 算法概念与描述&#xff0c;入门算法&#xff0c;基础算法&#xff0c;数值处理算法&#xff0c;排序算法&#xff0c;搜索算法&#xff…

软件测试炸了,作为从业者,你做好准备了吗?

软件测试行业已经发生很大变化&#xff0c;你跟上变化了吗&#xff1f; 岗位少不可怕&#xff0c;要求越来越高也不可怕&#xff0c;可怕的是&#xff0c;软件测试行业已经发生巨变&#xff0c;而你却原地踏步&#xff01;目前一线大厂更多倾向于招收测试开发&#xff0c;或者…

06. 数据结构之散列表

前言 散列表也叫作哈希表&#xff08;hash table&#xff09;&#xff0c;这种数据结构提供了键&#xff08;Key&#xff09;和值&#xff08;Value&#xff09;的映射关系。只要给出一个Key&#xff0c;就可以高效查找到它所匹配的Value&#xff0c;时间复杂度接近于O(1) 1.…

photoshop矫正扫描图片的倾斜问题以及修改图片内容

由于工程原因&#xff0c;资料需要重新梳理 1.扫描工程表格到电脑中 2.在ps中导入表格内容&#xff08;表格有时候是倾斜的&#xff09; 需要修正为正常状态&#xff0c;即垂直状态 设置步骤&#xff1a; 1.调整ps的背景颜色与所在图片的背景颜色一致 用吸管工具&#xff…

AbandonedConnectionCleanupThread$ConnectionFinalizerPhantomReference内存溢出

网上查了查资料&#xff0c;根据自己情况在这里整理了一下&#xff0c;供大家学习和参考。 目录 1、现象 2、mysql-connector-java 源码分析 3、解决方法 3.1、配置disableAbandonedConnectionCleanup 3.2、暴力解决方式-----定时GC 4、什么是虚引用 5、关联对象真的被回…

数据可视化:趋势类可视化图表大全

图表是处理数据的重要组成部分&#xff0c;因为它们是一种将大量数据压缩为易于理解的格式的方法。数据可视化可以让受众快速Get到重点。 数据可视化的图表类型极其丰富多样&#xff0c;而且每种都有不同的用例&#xff0c;通常&#xff0c;创建数据可视化最困难的部分是确定哪…

【Linux】常用命令的汇总学习

文章目录 1.目录切换命令2.目录操作命令3.把ls -l中包含字母file&#xff08;不区分大小写&#xff09;的内容输出4.统计txt中的某个字符串5.grep命令的使用6.linux查找当前目录下所有txt文件7.linux中的find命令8.查看系统所有的进程信息9.如何确定文件的类型10.tar解压缩11.U…

员工防范网络钓鱼攻击的10个实用技巧

你知道网络钓鱼攻击的危害吗&#xff1f;以下是网络钓鱼的定义及其引起关注的原因&#xff1a; Verizon 最近的一份报告显示&#xff0c;82&#xff05;的网络漏洞均由人为因素造成&#xff0c;比如窃取凭证、网络钓鱼攻击、社会工程学、冒名顶替、滥用或错误等。网络钓鱼攻击…

惊!掌握千问通义的关键,从这些必知内容开始!

今年快过半了&#xff0c;要说顶流话题还得是ChatGPT&#xff0c;相关话题的热度居高不下&#xff0c;而其从GPT-3.5到GPT-4的升级&#xff0c;也让我们深刻了解了什么叫一代版本一代神&#xff0c;从GPT-3.5到GPT-4&#xff0c;真的就是一个跨阶级式的升级。 技术内涵 ChatGPT…

某SRC的渗透测试实战

前言 因为不甘心被称作会只点鼠标的猴子&#xff0c;所以开始了一次某SRC漏洞挖掘&#xff0c;为期一个多星期。文章有点长&#xff0c;但请耐心看完&#xff0c;记录了完整的SRC漏洞挖掘实战 渗透过程 因为选择的幸运儿没有对测试范围进行规划&#xff0c;所以此次范围就是…

OPC UA客户端访问 OPC DA服务器

目标 用OPC UA客户端&#xff08;如UaExpert&#xff09;读取OPC DA服务器上的点。 原理 OPC DA是基于COM/DCOM的&#xff0c;传统OPC DA客户端访问非本机OPC DA服务时需要配置DCOM。OPC UA客户端无法直接访问 OPC DA服务&#xff0c;需要将OPC DA服务映射为OPC UA服务&#x…

【Excel技巧】3个限制权限,保护表格不被人随意改动

Excel表格是很多人工作中经常用到的办公软件&#xff0c;有时候做好表格发给对方后&#xff0c;总是担心会被不小心做了改动。 如果有这种顾虑&#xff0c;就一定要用上Excel表格的3个“限制权限”&#xff0c;可以根据不同的情况&#xff0c;设置不同保护。下面就来看看可以设…

LAMP配置安装

目录 一&#xff1a;LAMP 1、(平台)Linux 2、(前台)Apache 3、(后台)MySQL 4、(中间连接)PHP/Perl/Python 5. Lamp工作原理 二&#xff1a;编译安装Apache httpd服务 1.关闭防火墙&#xff0c;将安装Apache所需软件包传到/opt目录下 2.安装环境依赖包 3.配置软件模块…

打造繁荣社区:Solaris 与 Web3 合作的力量

在去中心化金融&#xff08;DeFi&#xff09;的动态格局中&#xff0c;Solaris 作为一股开创性力量涌现&#xff0c;为衍生品提供了强大的 Web3 基础设施。Solaris 成功的关键在于其充满活力且迅速增长的社区&#xff0c;该社区在塑造平台影响力和促进创新方面发挥着关键作用。…

C++ 新特性

1.auto、decltype 用于自动推断类型 2.自动追踪返回值类型 3. 列表初始化和列表方式类型收窄 //列表初始化 vector<int>res{1,2,3,4,5}; //防止类型收窄 int a 1024; char b a;//可以执行 char b{a};//报错 4.基于范围的for循环 vector<int>res{1,2,3,4}; fo…

“外行转网工,我只用了三个月”

大家好&#xff0c;我是老杨。 在这行发展了这么多年&#xff0c;经常会有人来问我&#xff0c;网工该怎么提升自己&#xff0c;又或是怎么入行。 其实这事儿不难想&#xff0c;技术工种最需要做的是什么&#xff0c;自然是提升技术。 而技术提升&#xff0c;途径也只有学习…