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

Postgresql源码(135)生成执行计划——Var的调整set_plan_references

1 总结

  • set_plan_references主要有两个功能:
    • 拉平:生成拉平后的RTE列表(add_rtes_to_flat_rtable)。
    • 调整:调整前每一层计划中varno的引用都是相对于本层RTE的偏移量。放在一个整体计划后,需要指向一个统一的RTE列表,所以需要把varno调整下指向拉平后的RTE表。
    • 例如下面计划中,RTE记录了6张表:
      • 1 → `{rtekind = RTE_RELATION, relid = 16656, inh = false, relkind = 114 ‘r’} -> student
      • 2 → `{rtekind = RTE_RELATION, relid = 16671, inh = false, relkind = 114 ‘r’} -> score
      • 3 → `{rtekind = RTE_JOIN, relid = 0, inh = false, relkind = 0 } -> {score join student}
      • 4 → `{rtekind = RTE_RELATION, relid = 16661, inh = false, relkind = 114 ‘r’} -> course
      • 5 → `{rtekind = RTE_JOIN, relid = 0, inh = false, relkind = 0 } -> {被优化掉的join course}
    • Result节点的第一列是STUDENT.sname,他的varno一开始是1,varattno是2,显然他不应该直接引用RTE中的某一张表,因为Result节点的数据应该使用下面SORT节点中取出来的,所以:
      • varno被调整为-2(表示引用OUTTER节点也就是LEFT树返回的结果)
      • varattno被调整1,表示从结果中拿第一列。
explain
SELECT STUDENT.sname, random(), SCORE.degree
FROM STUDENT
LEFT JOIN SCORE ON STUDENT.sno = SCORE.sno
LEFT JOIN COURSE ON SCORE.cno = COURSE.cno
ORDER BY STUDENT.sno;QUERY PLAN
------------------------------------------------------------------------------------Result  (cost=182.67..213.27 rows=2040 width=54)->  Sort  (cost=182.67..187.77 rows=2040 width=46)Sort Key: student.sno->  Hash Right Join  (cost=34.75..70.53 rows=2040 width=46)Hash Cond: (score.sno = student.sno)->  Seq Scan on score  (cost=0.00..30.40 rows=2040 width=12)->  Hash  (cost=21.00..21.00 rows=1100 width=42)->  Seq Scan on student  (cost=0.00..21.00 rows=1100 width=42)

上面用例经过set_plan_references调整前后的完整例子:
在这里插入图片描述

2 数据结构

PlannerInfo

当前查询优化的状态,包含了当前查询的所有信息:

  • 当前查询的目标列表(target list)
  • 子句(例如,WHERE、GROUP BY、ORDER BY 等)
  • 范围表(range table)
  • 可用的索引信息
  • 统计信息
  • 子查询和参数信息
  • 优化器的各种临时数据和结果

PlannerGlobal

全局结构,包含了跨多个查询级别的信息。例如一个包含子查询或CTE的查询中,每个子查询都会有自己的 PlannerInfo结构,会共享同一个PlannerGlobal。包含了:

  • 全局范围表(finalrtable)
  • 全局子计划列表
  • 全局初始化计划列表
  • 全局参数表达式列表
  • 重写规则和其他全局状态信息

varno宏

#define    INNER_VAR		(-1)	/* reference to inner subplan */
#define    OUTER_VAR		(-2)	/* reference to outer subplan */
#define    INDEX_VAR		(-3)	/* reference to index column */
#define    ROWID_VAR		(-4)	/* row identity column during planning */

3 set_plan_references

1 计算全局flat_rtable

set_plan_references → add_rtes_to_flat_rtable

首先把引用的rtable全部拉平到一个级别,重新排列RTE。

具体在PlannerGlobal中构造全局范围表finalrtable,所有子PlannerInfo共享的一套RTE。

	p *root->glob->finalrtable
$7 = {type = T_List, length = 5, max_length = 5, elements = 0x3085520, initial_elements = 0x3085520}

add_rtes_to_flat_rtable后生成五个RTE:

  • RangeTblEntry {rtekind = RTE_RELATION, relid = 16656, inh = false, relkind = 114 'r'}
  • RangeTblEntry {rtekind = RTE_RELATION, relid = 16671, inh = false, relkind = 114 'r'}
  • RangeTblEntry {rtekind = RTE_JOIN, relid = 0, inh = false, relkind = 0}
  • RangeTblEntry {rtekind = RTE_RELATION, relid = 16661, inh = false, relkind = 114 'r'}
  • RangeTblEntry {rtekind = RTE_JOIN, relid = 0, inh = false, relkind = 0}

PlannerInfo→PlannerGlobal:

2 开始修正RTE的引用

set_plan_references → set_plan_refs

2.1 处理Result

  • set_plan_refs

    • case T_Result: 处理result子树
    • plan->lefttree = set_plan_refs(root, plan->lefttree, rtoffset); 递归处理左树
    • plan->righttree = set_plan_refs(root, plan->righttree, rtoffset); 递归处理右树
  • 根据内层的sort节点,重新排列result节点的三个var的varno和varattno,result已经是最外层节点了,当前使用到的var还是从sort节点继承的,需要修复下。

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

set_plan_refs处理T_Result节点:

set_plan_refs......case T_Result:Result     *splan = (Result *) plan;if (splan->plan.lefttree != NULL)set_upper_references(root, plan, rtoffset);......// subplan 是 SORT节点// subplan->targetlist 中返回三列:STUDENT.sname, SCORE.degree,  STUDENT.sno// 注意缺了一列random函数subplan_itlist = build_tlist_index(subplan->targetlist);	
  • subplan->targetlist
    • varno = 1, varattno = 2, vartype = 1043
    • varno = 2, varattno = 3, vartype = 23
    • varno = 1, varattno = 1, vartype = 23
  • subplan_itlist
    • subplan_itlist->tlist = subplan->targetlist
    • subplan_itlist->vars[0] = {varno = 1, varattno = 2, resno = 1, varnullingrels = 0x0}
    • subplan_itlist->vars[1] = {varno = 2, varattno = 3, resno = 2, varnullingrels = ...}
    • subplan_itlist->vars[2] = {varno = 1, varattno = 1, resno = 3, varnullingrels = 0x0}
				foreach(l, plan->targetlist)...newexpr = fix_upper_expr(...)...// 计算完成plan->targetlist = output_targetlist;
  • output_targetlist
    • expr = 0x308f0c8, resno = 1, resname = 0x2f4d670 "sname"
      • varno = OUTER_VAR = -2, varattno = 1, vartype = 1043
    • expr = 0x308f1b8, resno = 2, resname = 0x2f4d7e8 "random"
      • funcid = 1598, funcresulttype = 701, funcretset = false
    • expr = 0x308f258, resno = 3, resname = 0x2f4d928 "degree"
      • varno = OUTER_VAR = -2, varattno = 2, vartype = 23
    • expr = 0x308f2f8, resno = 4, resname = 0x0, ressortgroupref = 1
      • varno = OUTER_VAR = -2, varattno = 3, vartype = 23

2.2 处理SORT

  • set_plan_refs
    • case T_Sort: 处理sort子树set_dummy_tlist_references
    • plan->lefttree = set_plan_refs(root, plan->lefttree, rtoffset); 递归处理左树
    • plan->righttree = set_plan_refs(root, plan->righttree, rtoffset); 递归处理右树

排序只需要引用下面一层的结果即可。

// These plan types don't actually bother to evaluate their
// targetlists, because they just return their unmodified input
// tuples.  Even though the targetlist won't be used by the
// executor, we fix it up for possible use by EXPLAIN (not to
// mention ease of debugging --- wrong varnos are very confusing).set_dummy_tlist_references

2.3 处理Hash Right Join

  • set_plan_refs
    • case T_HashJoin: 处理join子树set_join_references
    • plan->lefttree = set_plan_refs(root, plan->lefttree, rtoffset); 递归处理左树
    • plan->righttree = set_plan_refs(root, plan->righttree, rtoffset); 递归处理右树

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

4 用例

explain
SELECT STUDENT.sname, random(), SCORE.degree
FROM STUDENT
LEFT JOIN SCORE ON STUDENT.sno = SCORE.sno
LEFT JOIN COURSE ON SCORE.cno = COURSE.cno
ORDER BY STUDENT.sno;QUERY PLAN
------------------------------------------------------------------------------------Result  (cost=182.67..213.27 rows=2040 width=54)->  Sort  (cost=182.67..187.77 rows=2040 width=46)Sort Key: student.sno->  Hash Right Join  (cost=34.75..70.53 rows=2040 width=46)Hash Cond: (score.sno = student.sno)->  Seq Scan on score  (cost=0.00..30.40 rows=2040 width=12)->  Hash  (cost=21.00..21.00 rows=1100 width=42)->  Seq Scan on student  (cost=0.00..21.00 rows=1100 width=42)

相关文章:

Postgresql源码(135)生成执行计划——Var的调整set_plan_references

1 总结 set_plan_references主要有两个功能: 拉平:生成拉平后的RTE列表(add_rtes_to_flat_rtable)。调整:调整前每一层计划中varno的引用都是相对于本层RTE的偏移量。放在一个整体计划后,需要指向一个统一…...

Python魔法之旅专栏(导航)

目录 推荐阅读 1、Python筑基之旅 2、Python函数之旅 3、Python算法之旅 4、博客个人主页 首先,感谢老铁们一直以来对我的支持与厚爱,让我能坚持把Python魔法方法专栏更新完毕! 其次,为了方便大家查阅,我将此专栏…...

Python第二语言(五、Python文件相关操作)

目录 1. 文件编码的概念 2. 文件的读取操作 2.1 什么是文件 2.2 open()打开函数 2.3 mode常用的三种基础访问模式 2.4 文件操作及案例 3. 文件的写入操作及刷新文件:write与flush 4. 文件的追加操作 5. 文件操作的综合案例(文件备份操作&#x…...

Vue3 组合式 API:依赖注入(四)

provide() provide() 函数是用于依赖注入的一个关键部分。这个函数允许你在组件树中提供一个值或对象,使得任何子组件(无论层级多深)都能够通过 inject() 函数来访问这些值。 import { provide, ref } from vue; export default { setup(…...

Vue如何引入ElementUI并使用

Element UI详细介绍 Element UI是一个基于Vue 2.0的桌面端组件库,旨在构建简洁、快速的用户界面。由饿了么前端团队开发,提供丰富的组件和工具,帮助开发者快速构建高质量的Vue应用,并且以开放源代码的形式提供。 1. VueElementU…...

VS2019 QT无法打开 源 文件 “QTcpSocket“

VS2019 QT无法打开 源 文件 "QTcpSocket" QT5.15.2_msvc2019_64 严重性 代码 说明 项目 文件 行 禁止显示状态 错误(活动) E1696 无法打开 源 文件 "QTcpSocket" auto_pack_line_demo D:\vs_qt_project\auto_pack_line_de…...

【Golang】Map 稳定有序遍历的实现与探索:保序遍历之道

【Golang】Map 稳定有序遍历的实现与探索:保序遍历之道 大家好 我是寸铁👊 总结了一篇【Golang】Map 稳定有序遍历的实现与探索:保序遍历之道✨ 喜欢的小伙伴可以点点关注 💝 前言🍎 在计算机科学中,数据结…...

使用Nextjs学习(学习+项目完整版本)

创建项目 运行如下命令 npx create-next-app next-create创建项目中出现的各种提示直接走默认的就行,一直回车就行了 创建完成后进入到项目运行localhost:3000访问页面,如果和我下面页面一样就是创建项目成功了 整理项目 将app/globals.css里面的样式都删除,只留下最上面三…...

KUKA机器人KRC5控制柜面板LED显示

对于KUKA机器人新系列控制柜KRC5控制柜来说,其控制柜面板LED布局如下图: 其中①②③④分别为: 1、机器人控制柜处于不同状态时,LED显示如下: 2、机器人控制柜正在运行时: 3、机器人控制柜运行时出现的故障…...

为什么选择Python作为AI开发语言

为什么Python适合AI 在当前的科技浪潮中,人工智能(AI)无疑是最热门的话题之一。无论是自动驾驶、智能推荐还是自然语言处理,AI都在不断改变我们的生活。而在这场技术革命中,Python作为主要的编程语言之一,…...

【算法篇】求最长公共前缀JavaScript版本

题目描述 给你一个大小为 n 的字符串数组 strs &#xff0c;其中包含n个字符串 , 编写一个函数来查找字符串数组中的最长公共前缀&#xff0c;返回这个公共前缀。 数据范围&#xff1a; 数据范围:0<n<5000&#xff0c;0<len(strsi)< 5000 进阶:空间复杂度 O(1)&a…...

搭建RocketMQ主从异步集群

搭建RocketMQ主从异步集群 1、RocketMQ集群模式 为了追求更好的性能&#xff0c;RocketMQ的最佳实践方式都是在集群模式下完成的。RocketMQ官方提供了三种集群搭建方式&#xff1a; 2主2从异步通信方式&#xff1a;使用异步方式进行主从之间的数据复制。吞吐量大&#xff0c;…...

最大子段和问题

最大子段和问题 分数 15 全屏浏览 切换布局 作者 王东 单位 贵州师范学院 最大子段和问题。给定由n个整数组成的序列&#xff0c;求序列中子段的最大和&#xff0c;若所有整数均为负整数时定义最大子段和为0。 输入格式: 第一行输入整数个数n&#xff08;1≤n≤1000&…...

Vue3中的常见组件通信之mitt

Vue3中的常见组件通信之mitt 概述 ​ 在vue3中常见的组件通信有props、mitt、v-model、 r e f s 、 refs、 refs、parent、provide、inject、pinia、slot等。不同的组件关系用不同的传递方式。常见的撘配形式如下表所示。 组件关系传递方式父传子1. props2. v-model3. $refs…...

MySQL快速入门(极简)

SQL 介绍及 MySQL 安装 一、实验简介 本课程为实验楼提供的 MySQL 实验教程&#xff0c;所有的步骤都在实验楼在线实验环境中完成&#xff0c;学习中请按照实验步骤依次操作。 本课程为 SQL 基本语法及 MySQL 基本操作的实验&#xff0c;理论内容较少&#xff0c;动手实践多…...

CentOS7安装NVIDIA显卡驱动指引【笔记】

CentOS7安装NVIDIA显卡驱动指引【笔记】 实践设备:华硕FX-PRO(NVIDIA GeForce GTX 960M) 环境准备: 1、将系统安装到设备上正常运行; 2、设备网络调试,可以正常访问外网; 3、配置ssh服务(非必要,根据实际情况)。 说明: 本文档所提供的指引和参考主要基于特定实践…...

【RabbitMQ】RabbitMQ配置与交换机学习

【RabbitMQ】RabbitMQ配置与交换机学习 文章目录 【RabbitMQ】RabbitMQ配置与交换机学习简介安装和部署1. 安装RabbitMQ2.创建virtual-host3. 添加依赖4.修改配置文件 WorkQueues模型1.编写消息发送测试类2.编写消息接收&#xff08;监听&#xff09;类3. 实现能者多劳 交换机F…...

常见排序算法,快排,希尔,归并,堆排

后面的排序中都要用到的函数 //交换 void Swap(int* p1, int* p2) {int* tmp *p1;*p1 *p2;*p2 tmp; } 包含的头文件 "Sort.h" #pragma once #include<stdio.h> #include<stdlib.h> #include<assert.h> #include<time.h> #include<s…...

语法的时态1——一般现在时(1)

定义&#xff1a;一般现在时用来表示经常发生的动作&#xff0c;以及客观事实。 一般现在时的构成以及标志词 1.一般现在时的结构 &#xff08;1&#xff09;主系表结构 构成&#xff1a;主语be(am,is,ear)其他。属于状态句。 I…...

JAVA:在IDEA引入本地jar包的方法并解决打包scope为system时发布无法打包进lib的方案

一.引入本地Jar包的步骤 有时maven依耐的包是本地的jar包&#xff0c;此时需要进行以下步骤设置。 步骤1.在pom.xml中添加插件设置,将system范围包含进来&#xff0c;此设置是为了在打包时&#xff0c;本地jar包自动生成到部署包里。(若无法打进包&#xff0c;请参考下文的方…...

使用VSCode开发Django指南

使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架&#xff0c;专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用&#xff0c;其中包含三个使用通用基本模板的页面。在此…...

【位运算】消失的两个数字(hard)

消失的两个数字&#xff08;hard&#xff09; 题⽬描述&#xff1a;解法&#xff08;位运算&#xff09;&#xff1a;Java 算法代码&#xff1a;更简便代码 题⽬链接&#xff1a;⾯试题 17.19. 消失的两个数字 题⽬描述&#xff1a; 给定⼀个数组&#xff0c;包含从 1 到 N 所有…...

CMake基础:构建流程详解

目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

基于Uniapp开发HarmonyOS 5.0旅游应用技术实践

一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架&#xff0c;支持"一次开发&#xff0c;多端部署"&#xff0c;可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务&#xff0c;为旅游应用带来&#xf…...

使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装

以下是基于 vant-ui&#xff08;适配 Vue2 版本 &#xff09;实现截图中照片上传预览、删除功能&#xff0c;并封装成可复用组件的完整代码&#xff0c;包含样式和逻辑实现&#xff0c;可直接在 Vue2 项目中使用&#xff1a; 1. 封装的图片上传组件 ImageUploader.vue <te…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)

设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile&#xff0c;新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...

IT供电系统绝缘监测及故障定位解决方案

随着新能源的快速发展&#xff0c;光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域&#xff0c;IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选&#xff0c;但在长期运行中&#xff0c;例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...

Spring数据访问模块设计

前面我们已经完成了IoC和web模块的设计&#xff0c;聪明的码友立马就知道了&#xff0c;该到数据访问模块了&#xff0c;要不就这俩玩个6啊&#xff0c;查库势在必行&#xff0c;至此&#xff0c;它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据&#xff08;数据库、No…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。

1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj&#xff0c;再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...

【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统

目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索&#xff08;基于物理空间 广播范围&#xff09;2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...