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

查询优化-提升子查询-UNION类型

瀚高数据库
目录
文档用途
详细信息

文档用途

剖析UNION类型子查询提升的条件和过程

详细信息

注:图片较大,可在浏览器新标签页打开。

SQL:

SELECT * FROM score sc, LATERAL(SELECT * FROM student WHERE sno = 1 UNION ALL SELECT * FROM student WHERE sno = sc .sno) st WHERE st.sno > 0;

查询树结构:

分析该查询树,主查询包含2个RangeTblEntry:sc和st;其中st这个表的类型是子查询,包含2个RangeTblEntry,从SQL也可以看出这2个RangeTblEntry对应两个select查询,按照Query结构去分层该查询树为3层。

稍微简化一下,结构如下图所示:

在这里插入图片描述

打印该SQL的执行计划:

image.png

根据执行计划和查询树优化前后对比,对于UNION类型的子查询提升主要是将UNION两侧子查询提升,反映在查询树中即是这2个子查询类型的RangeTblEntry添加到主查询对应的rtable队列中,3层查询优化为2层查询结构。

提升流程:查找范围表中可以提升到父查询中的子查询。如果子查询没有特殊的特性,比如分组/聚合,那么我们可以将其合并到父查询的联接树中。此外,简单的 UNION ALL 结构的子查询可以转换为“追加关系”。

void pull_up_subqueries(PlannerInfo *root){Assert(IsA(root->parse->jointree, FromExpr));root->parse->jointree = (FromExpr *)pull_up_subqueries_recurse(root, (Node *) root->parse->jointree,NULL, NULL);Assert(IsA(root->parse->jointree, FromExpr));}

jointree中包含了FROM…WHERE…所引用的表,该递归结构通过pull_up_subqueries_recurse对其进行递归处理,所以优化执行时先去深度遍历FromExpr中的列表中的每一项成员:

if (IsA(jtnode, FromExpr)){FromExpr   *f = (FromExpr *) jtnode;ListCell   *l;Assert(containing_appendrel == NULL);foreach(l, f->fromlist){lfirst(l) = pull_up_subqueries_recurse(root, lfirst(l),lowest_outer_join,NULL);}}

如果RangeTblEntry是subquery类型并且满足简单子查询条件,使用pull_up_simple_union_all处理,该函数接受3个参数,分别是:查询树上下文, RangeTblRef, RangeTblEntry。

int varno = ((RangeTblRef *) jtnode)->rtindex;RangeTblEntry *rte = rt_fetch(varno, root->parse->rtable);if (rte->rtekind == RTE_SUBQUERY &&is_simple_union_all(rte->subquery))return pull_up_simple_union_all(root, jtnode, rte);

pull_up_simple_union_all:

根据优化后的查询树结构,提升的主要目的是把三个层次变成两个层次,那么如果“子子查询”中引用了顶层的列属性,那么这些变量应该提升一个层次,也就是调用incrementVarSublevelsUp_ rtable(rtable, -1 , 1 )。比如本例SQL:SELECT * FROM student WHERE sno = sc .sno , sc.sno 就引用了第一个层次中的列表量,它的 Var >varlevlesup 的原值是 2(相对值),子查询提升之后应该变成1。

image.png                                   image.png

在这里插入图片描述

2.下发LATERAL,本例中是(SELECT * FROM student WHERE sno = 1)和 ( SELECT * FROM student WERE sno = sc.sno )这两个子查询都变成 LATERAL,而不是只是针对引用父查询属性子查询才会拥有LATERAL语义。

image.png image.png         image.png

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

if (rte->lateral){ListCell   *rt;foreach(rt, rtable){RangeTblEntry *child_rte = (RangeTblEntry *) lfirst(rt);Assert(child_rte->rtekind == RTE_SUBQUERY);child_rte->lateral = true;}}

3.把第三层次的两个RangeTblEntry:(SELECT * FROM student WHERE sno = 1)和(SELECT * FROM student WHERE sno = sc.sno )两个子查询附加到第一层的 Query->rtable 列表中,在这第3步过后,后续的子查询的rtindex都将加上父查询rtindex作为偏置值。

/** Append child RTEs (and their perminfos) to parent rtable.*/CombineRangeTables(&root->parse->rtable, &root->parse->rteperminfos,rtable, subquery->rteperminfos);{*dst_rtable = list_concat(*dst_rtable, src_rtable);...}

4.开始对 subquery->setOperations 进行遍历 (pull_up_union_leaf_queries 函数),为其中的每个子查询生成一个AppendRelInfo 节点,在本例中为( SELECT * FROM student WHERE sno = 1〕和 (SELECT * FROM student WHERE sno = sc.sno )生成两个 AppendRelInfo 节点,这种类型的节点是记录到查询树的上下文中,在查询树中看不到。

SetOperationStmt *op = (SetOperationStmt *) setOp;/* Recurse to reach leaf queries */pull_up_union_leaf_queries(op->larg, root, parentRTindex, setOpQuery,childRToffset);pull_up_union_leaf_queries(op->rarg, root, parentRTindex, setOpQuery,childRToffset);appinfo = makeNode(AppendRelInfo);appinfo->parent_relid = parentRTindex;appinfo->child_relid = childRTindex;appinfo->parent_reltype = InvalidOid;appinfo->child_reltype = InvalidOid;make_setop_translation_list(setOpQuery, childRTindex, appinfo);appinfo->parent_reloid = InvalidOid;root->append_rel_list = lappend(root->append_rel_list, appinfo);
  1. 简单回顾这种类型子查询流程如下图:

image.png

到此为止,还有一个需要解决的问题:子查询提升将对应的RangeTblEntry添加到了父查询的rtable中,而且过程中更新了rtindex(第4步),这个新的RangeTblEntry不会在父查询的FromExpr中出现,所以构造完ApendRelInfo后,需要对子查询构造新的RangeTblRef,填充新的rtindex, 然后执行pull_up_subqueries_recurse。

rtr = makeNode(RangeTblRef);rtr->rtindex = childRTindex;(void) pull_up_subqueries_recurse(root, (Node *) rtr,NULL, appinfo);

最后就能得到优化后的查询树结构。

相关文章:

  • 国内IP切换软件:解锁网络世界的新钥匙
  • 【八大排序】一篇文章搞定所有排序
  • 企业系统对接必知事项-请您查收
  • vmware,linux,centos7,NAT模式下的网络配置
  • 定义类强化——移动的圆
  • Composer常见错误解决
  • “直播曝光“有哪些媒体直播分流资源?
  • Java基础语法(八)| 继承
  • 基于Hive的天气情况大数据分析系统(通过hive进行大数据分析将分析的数据通过sqoop导入到mysql,通过Django基于mysql的数据做可视化)
  • ArcGIS矢量裁剪矢量
  • SpringBoot --条件注解与属性绑定
  • Contos7 安装 Maven
  • sqlite3的安装
  • 前端Ajax请求从后端获取二进制文件并下载
  • STM32学习笔记(9_2)- USART串口外设
  • Angular js 常用指令ng-if、ng-class、ng-option、ng-value、ng-click是如何使用的?
  • bootstrap创建登录注册页面
  • canvas 绘制双线技巧
  • CSS3 变换
  • HashMap ConcurrentHashMap
  • JavaScript异步流程控制的前世今生
  • Java小白进阶笔记(3)-初级面向对象
  • Java新版本的开发已正式进入轨道,版本号18.3
  • JS 面试题总结
  • Linux下的乱码问题
  • Mocha测试初探
  • SAP云平台里Global Account和Sub Account的关系
  • TCP拥塞控制
  • VuePress 静态网站生成
  • WinRAR存在严重的安全漏洞影响5亿用户
  • 从地狱到天堂,Node 回调向 async/await 转变
  • 从伪并行的 Python 多线程说起
  • 读懂package.json -- 依赖管理
  • 短视频宝贝=慢?阿里巴巴工程师这样秒开短视频
  • 如何用vue打造一个移动端音乐播放器
  • 微信小程序实战练习(仿五洲到家微信版)
  • 微信支付JSAPI,实测!终极方案
  • 新书推荐|Windows黑客编程技术详解
  • postgresql行列转换函数
  • UI设计初学者应该如何入门?
  • # 学号 2017-2018-20172309 《程序设计与数据结构》实验三报告
  • (1)(1.9) MSP (version 4.2)
  • (rabbitmq的高级特性)消息可靠性
  • (安卓)跳转应用市场APP详情页的方式
  • (附源码)springboot电竞专题网站 毕业设计 641314
  • (论文阅读23/100)Hierarchical Convolutional Features for Visual Tracking
  • (十)【Jmeter】线程(Threads(Users))之jp@gc - Stepping Thread Group (deprecated)
  • (算法)Game
  • (一)搭建springboot+vue前后端分离项目--前端vue搭建
  • ./和../以及/和~之间的区别
  • .net core 依赖注入的基本用发
  • .net core控制台应用程序初识
  • .NET 简介:跨平台、开源、高性能的开发平台
  • .NET使用HttpClient以multipart/form-data形式post上传文件及其相关参数
  • .project文件