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后
在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/162836.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/162836.shtml
英文地址,請注明出處:http://en.pswp.cn/news/162836.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

nginx編譯安裝

1.下載nginx: 地址:http://nginx.org/en/download.html 2.安裝依賴 安裝gcc: yum install -y gcc安裝pcre庫 yum install -y pcre pcre-devel安裝zlib庫: yum install -y zlib zlib-devel3.安裝nginx ./configure --prefix/usr/local/ngi…

Spark SQL將Hive表中的數據寫入到MySQL數據庫中

import org.apache.spark.sql.SparkSessionobject HiveToMySQL {def main(args: Array[String]): Unit {// 創建SparkSessionval spark SparkSession.builder().appName("HiveToMySQL").enableHiveSupport().getOrCreate()// 讀取Hive表數據val hiveDF spark.tabl…

一體化大氣環境監測設備實時守護我們的空氣質量

WX-CSQX12 隨著空氣污染問題的日益嚴重,大氣環境監測設備成為了我們生活中不可或缺的一部分。而一體化的大氣環境監測設備,更是為我們的環境保護工作帶來了更多的便利和效益。 一體化大氣環境監測設備是一種集成了多種功能于一體的環保設備,…

BootStrap【表格二、基礎表單、被支持的控件、表單狀態】(二)-全面詳解(學習總結---從入門到深化)

目錄 表格二 表單_基礎表單 表單_被支持的控件 表單_表單狀態 表格二 緊縮表格 通過添加 .table-condensed 類可以讓表格更加緊湊&#xff0c;單元格中的內補&#xff08;padding&#xff09;均會減半 <table class"table table-condensed table-bordered"…

學習量化交易如何入門?

Python 量化入門很簡單&#xff0c;只需 3 步就能快速上手! 題主在程序方向沒有相關經驗&#xff0c;今天就從量化行業的通用語言-Python 著手&#xff0c;教大家如何快速入門。 一、準備工作 在開始 Python 編程之前&#xff0c;首先需要確保你的計算機上安裝了合適的 Pytho…

【深度學習】Transformer簡介

近年來&#xff0c;Transformer模型在自然語言處理&#xff08;NLP&#xff09;領域中橫掃千軍&#xff0c;以BERT、GPT為代表的模型屢屢屠榜&#xff0c;目前已經成為了該領域的標準模型。同時&#xff0c;在計算機視覺等領域中&#xff0c;Transformer模型也逐漸得到了重視&a…

【PythonGIS】基于Python面矢量轉換線矢量

今天有些不一樣&#xff0c;發這篇文章并不是項目需要。單純的想到有這個功能沒使用Python實現&#xff0c;所以就去研究了一下&#xff0c;第一時間就和大家分享。如何使用Python的osgeo庫實現面矢量數據與線矢量數據的互相轉換。 一、導入所需庫 import os from osgeo impor…

論文速讀《DeepFusion: Lidar-Camera Deep Fusion for Multi-Modal 3D Object Detection》

概括主要內容 文章《DeepFusion: Lidar-Camera Deep Fusion for Multi-Modal 3D Object Detection》提出了兩種創新技術&#xff0c;以改善多模態3D檢測模型的性能&#xff0c;通過更有效地融合相機和激光雷達傳感器數據來提高對象檢測的準確性&#xff0c;尤其是在行人檢測方面…

自動化提交git

1.前要 這里只是講解如何在Windows上創建自動化腳本/程序來達到自動pull、commit、push&#xff0c;減少冗余的倉庫更新工作&#xff0c;避免在多平臺下合作造成版本沖突等。 2.原理 使用Windows下默認的cmd/bat腳本編寫代碼。 只需要在網絡上查詢一些相關的語法&#xff0…

2023亞太杯數學建模C題思路 - 我國新能源電動汽車的發展趨勢

1 賽題 問題C 我國新能源電動汽車的發展趨勢 新能源汽車是指以先進技術原理、新技術、新結構的非常規汽車燃料為動力來源( 非常規汽車燃料指汽油、柴油以外的燃料&#xff09;&#xff0c;將先進技術進行汽車動力控制和驅動相結 合的汽車。新能源汽車主要包括四種類型&#x…

【計算思維】藍橋杯STEMA 科技素養考試真題及解析 6

1、明明買了一個掃地機器人&#xff0c;可以通過以下指令控制機器人運動: F:向前走 10 個單位長度 L:原地左轉 90 度 R:原地右轉 90 度 機器人初始方向向右&#xff0c;需要按順序執行以下那條指令&#xff0c;才能打掃完下圖中的道路 A、F-L-F-R-F-F-R-F-L-F B、F-R-F-L-F-F…

h5如何使用navigateBack回退到微信小程序頁面并攜帶參數

前言 在h5中使用navigateBack回退到微信小程序頁面很常見&#xff0c;但是有一種交互需要在回退之后的頁面可以得到通知&#xff0c;拿到標識之后&#xff0c;進行某些操作&#xff0c;這樣的話&#xff0c;由于微信官方并沒有直接提供這樣的api&#xff0c;就需要我們開動腦筋…

視頻剪輯有妙招:批量置入封面,輕松提升視頻效果

隨著社交媒體的興起&#xff0c;視頻已經成為分享和交流的重要方式。無論是專業的內容創作者還是普通的社交媒體用戶&#xff0c;都要在視頻剪輯上下一番功夫&#xff0c;才能讓視頻更具吸引力。而一個吸引的封面往往能在一瞬間抓住眼球&#xff0c;提高點擊率。還在因如何選擇…

【SpringBoot】Redisson 分布式鎖注解和 @Transactional 注解一起使用問題

一、前言 平時使用切面去加分布式鎖&#xff0c;是先開啟事務還是先嘗試獲得鎖&#xff1f;這兩者有啥區別&#xff1f; 業務中怎么控制切面的順序&#xff1f;切面的順序對事務的影響怎么避免&#xff1f; 下面程序分析&#xff1a; OverrideTransactionalpublic ReceiveH5…

uni-app - 彈出框

目錄 1.基本介紹 2.原生uinapp 通過uni.showActionSheet實現 3.使用組件 Popup 彈出層 ③效果展示 1.基本介紹 彈出框讓我們在需要時在屏幕底部彈出一個菜單&#xff0c;它通常用于在各種應用程序中進行選擇操作。Uniapp為我們提供了基本的底部彈出框組件&#xff0c;但它也有…

OpenSearch開發環境安裝Docker和Docker-Compose兩種方式

文章目錄 簡介常用請求創建映射寫入數據查詢數據其他 安裝Docker方式安裝OpenSearch安裝OpenSearchDashboard Docker-Compose方式Docker-Compose安裝1.設置主機環境2.下載docker-compose.yml文件3.啟動docker-compose4.驗證 問題問題1&#xff1a;IPv4 forwarding is disabled.…

如何搭建Zblog網站并通過內網穿透將個人博客發布到公網

文章目錄 1. 前言2. Z-blog網站搭建2.1 XAMPP環境設置2.2 Z-blog安裝2.3 Z-blog網頁測試2.4 Cpolar安裝和注冊 3. 本地網頁發布3.1. Cpolar云端設置3.2 Cpolar本地設置 4. 公網訪問測試5. 結語 1. 前言 想要成為一個合格的技術宅或程序員&#xff0c;自己搭建網站制作網頁是繞…

Altium Designer學習筆記11

畫一個LED的封裝&#xff1a; 使用這個SMD5050的封裝。 我們先看下這個芯片的功能說明&#xff1a; 5050貼片式發光二極管&#xff1a; XL-5050 是單線傳輸的三通道LED驅動控制芯片&#xff0c;采用的是單極性歸零碼協議。 數據再生模塊的功能&#xff0c;自動將級聯輸出的數…

CSGO搬磚干貨,全網最詳細教學!

CSGO游戲搬磚全套操作流程及注意事項&#xff08;第一課&#xff09; 在電競游戲中&#xff0c;CSGO&#xff08;Counter-Strike: Global Offensive&#xff09;被廣大玩家譽為經典之作。然而&#xff0c;除了在游戲中展現個人實力和團隊合作外&#xff0c;有些玩家還將CSGO作為…

Java之API(上)

前言&#xff1a; 這一次內容主要是圍繞Java開發中的一些常用類&#xff0c;然后主要是去學習這些類里面的方法。 一、高級API&#xff1a; (1)介紹&#xff1a;API指的是應用程序編程接口&#xff0c;API可以讓編程變得更加方便簡單。Java也提供了大量API供程序開發者使用&…