子查询的处理
说实话,本人在没看PG之前,一直看mysql的文档里面讲子查询,什么From、drived子查询啥的,一直晕乎乎的。但是在看了PG代码之后,终于感觉略微明白了点。
具体说来,SQL里面,出现在rtable里面的子查询才可以称为是subquery,而出现在过滤条件(例如expression)中的被称为sublink。
例如:
select count(t1.a), tt.b from t1, (select t2.b, t2.c from t2) as tt
where t1.a in (select d from t3) and t1.a = tt.c
group by tt.b
having count(t1.a) < (select max(t3.a) from t3)
很明显,select t2.b from t2是subquery,而select c from t3 select max(t3.a) from t3都是sublink。
对于这个实例,PG会先将jointree中含有的sublink转成左半连接的subquery,生成一个新的jointree(见pull_up_sublink),然后将jointree中简单的subquery提上来(pull_up_subqueries)如是上面的SQL会被改写成如下的SQL:
select count(t1.a), t2.b from (t1, t2,) semi joi t3 on ( t1.a = t3.d ))
where t1.a = t2.c
group by t2.b
having count(t1.a) < (select max(t3.a) from t3)
注意 semi join实际上是数据库内部的概念,不是一个标准token。被pullup的sublink一般都是简单的SQL, 而且是exist in 或是any条件中的,具体见代码。而对于在jointree中的不能pullup的sublink以及having语句中sublink,实际上是在pull_up_sublink和pull_up_subqueries之后处理的(见preprocess_expression)。这些sublink,分为两种,一种是的独立sublink,这类sublink的SQL中不引用上层的Query中的变量(var);另外一种就是相关的sublink,引用了上层的var。
对于独立的sublink, 查询优化器会为之生成initplan,initplan只会被执行一次,但是存储了结果,having 条件通过变量编号来引用这个initplan。
如果是关联的sublink,查询优化器会为之生成subplan。外围的having对应的expression在执行时(实际就是一个agg的filter),会传入所引用的var的实际值,然后执行这个subplan,来获得expression的结果。
好了,在研究了单机的PG如何处理子查询之后,下面我们将描述ppg_fdw如何处理子查询的SQL.
首先,对于出现在jointree中的sublink,ppg_planner直接调用PG的接口(pull_up_sublink,pull_up_subqueries)来改写Query,最终变成不存在子查询的SQL。例如,对于这条SQL实例:
select
o_orderpriority,
count(*) as order_count
from
orders
where
o_orderdate >= date '1993-07-01'
and o_orderdate < date '1993-07-01' + interval '3' month
and exists (
select
*
from
lineitem
where
l_orderkey = o_orderkey
and l_commitdate < l_receiptdate
)
group by
o_orderpriority
order by
o_orderpriority
LIMIT 1;
ppg_planner会将sublink消灭之后只剩下semi join,然后采用和前面处理join和agg的方式生成全局最优plan以及下推的子计划(略去)。
而对于下面的SQL,实际上就需要initplan了:
select
ps_partkey,
sum(ps_supplycost * ps_availqty) as value
from
partsupp,
supplier,
nation
where
ps_suppkey = s_suppkey
and s_nationkey = n_nationkey
and n_name = 'PERU'
group by
ps_partkey having
sum(ps_supplycost * ps_availqty) > (
select
sum(ps_supplycost * ps_availqty) * 0.0001000000
from
partsupp,
supplier,
nation
where
ps_suppkey = s_suppkey
and s_nationkey = n_nationkey
and n_name = 'PERU'
)
order by
value desc
LIMIT 1;
因为
select
sum(ps_supplycost * ps_availqty) * 0.0001000000
from
partsupp,
supplier,
nation
where
ps_suppkey = s_suppkey
and s_nationkey = n_nationkey
and n_name = 'PERU'
是一个独立的SQL,因此ppg_planner会为之生成一个plan,然后将这个plan的编号塞入上层的havingClause的expression中被引用。
而对于下面这个例子,则彻底需要subplan:
select
s_acctbal,
s_name,
n_name,
p_partkey,
p_mfgr,
s_address,
s_phone,
s_comment
from
part,
supplier,
partsupp,
nation,
region
where
p_partkey = ps_partkey
and s_suppkey = ps_suppkey
and p_size = 41
and p_type like '%TIN'
and s_nationkey = n_nationkey
and n_regionkey = r_regionkey
and r_name = 'AFRICA'
and ps_supplycost = (
select
min(ps_supplycost)
from
partsupp,
supplier,
nation,
region
where
p_partkey = ps_partkey
and s_suppkey = ps_suppkey
and s_nationkey = n_nationkey
and n_regionkey = r_regionkey
and r_name = 'AFRICA'
)
order by
s_acctbal desc,
n_name,
s_name,
p_partkey
LIMIT 100;
主要是havingcluase的子查询是一个相关的子查询,引用了part表的p_partkey字段。
对于出现在fromclause中的subquery, ppg_planner会尽力在pull_subqueries中消灭之,一般无法pullup的subquery含有agg。如果存在这样的pullup的subquery,那么就要通过ppg_planner来生成子plan。
例如对于这个SQL实例:
select
supp_nation,
cust_nation,
l_year,
sum(volume) as revenue
from
(
select
n1.n_name as supp_nation,
n2.n_name as cust_nation,
extract(year from l_shipdate) as l_year,
l_extendedprice * (1 - l_discount) as volume
from
supplier,
lineitem,
orders,
customer,
nation n1,
nation n2
where
s_suppkey = l_suppkey
and o_orderkey = l_orderkey
and c_custkey = o_custkey
and s_nationkey = n1.n_nationkey
and c_nationkey = n2.n_nationkey
and (
(n1.n_name = 'KENYA' and n2.n_name = 'VIETNAM')
or (n1.n_name = 'VIETNAM' and n2.n_name = 'KENYA')
)
and l_shipdate between date '1995-01-01' and date '1996-12-31'
) as shipping
group by
supp_nation,
cust_nation,
l_year
order by
supp_nation,
cust_nation,
l_year
LIMIT 1;
实际上可以将fromclause里面那个子查询pullup,最终变成一个没有子查询的SQL,然后生成全局plan。可以这样处理的TPCH的SQL实例实际上还有若干个,这里就不列举了。
而对于下面这个SQL,则需要处理子查询了。
select
c_count,
count(*) as custdist
from
(
select
c_custkey,
count(o_orderkey)
from
customer left outer join orders on
c_custkey = o_custkey
and o_comment not like '%pending%accounts%'
group by
c_custkey
) as c_orders (c_custkey, c_count)
group by
c_count
order by
custdist desc,
c_count desc
LIMIT 1;
ppg_planner会为这条SQL中的子查询首先生成一个plan(为了方便,我们称为子plan),然后为上层的SQL生成一个plan(我们称为父plan)。逻辑上全局plan可以如下表示:
-------------------------
- (limit) - 父plan
- | -
- (sort) -
- | -
- (agg) -
- | -
- (foreign_scan) -
- | -
--------------------------
|
--------------------------
- (agg) -
- | -
- (foreign_scan) - 子plan
--------------------------
(由于这个iteye实在垃圾,上传图片老失败,只能这样讲究了)
父plan的叶子节点是foreign_scan,而这个foreign_scan的输入参数包括要下推的SQL以及子plan的id。
这个plan执行时,会分为两步:一,在executor执行父plan到foreign_scan时,会根据参数,先执行一个建立临时表的语句,然后执行子plan,从子plan获得结果插入临时表;二,一旦完成临时表数据的插入之后,执行父plan,从foreign_scan到二次聚集agg到sort最后到limit。
对于这种子查询处理,需要根据到子查询生成数据量来决定数据的分布方式:如果子查询的数据量小,可以认为是新生成了一个dimension表,并且这时的rangetable就是这个子查询,就像上面的例子,那么可以考虑将子查询的结果在DQP的本地进行处理,那么需要在上图父plan的foreign_scan上面插入一个subquery,省去了在OP上建立临时表和和插入数据的开销;如果子查询的数据量很小,并且还要和rangetable做join,这就要考虑rangetable其他表中是否含有fact表了,如果含有fact表,那么需要将这个新的临时表做全分布了,在每个OP上都建立临时表并都有一个份数据,如果做join的其他全是dimension表,那么这个SQL就演变成了对只含有dimension表的操作了,需要选择一个负载低的OP建立临时表插入数据后,将SQL转发给其处理;如果子查询的数据量比较大,那么认为新产生了一个fact表,需要根据join的字段做重分布,然后下推SQL。具体怎么处理关键需要建立一个统一的模型来估算代价,可能需要向PG的pg_catalog加入一个新的meta表,这个需要进一步研究,To be Done。
分享到:
相关推荐
ppg_fdw A distributed parallel query engine, based on fdw and hooks of PG.Our idea is to create a shared-nothing system, which is composed many pgsql servers. For these pgsql servers, one server (we ...
标题中的"datasrc_PPG.rar_PPG信号_datasrc_PPG_ppg data download_心电PPG信号_心电信"揭示了这是一个与心电图(ECG)和光体积描记术(Photoplethysmography,简称PPG)信号相关的数据资源。PPG是一种非侵入性的...
本压缩包文件“PPG_features-master_welcomee1m_ppg特征提取_PPG信号处理_PPG信号处理代码_PPG_”主要包含了与PPG信号预处理和特征提取相关的代码资源,适合学习和参考。 首先,我们来了解PPG信号的基本原理。PPG...
《PyPI官网下载:ppg_common-1.14.tar.gz——Python库在分布式环境中的应用》 在Python的世界里,PyPI(Python Package Index)是开发者们分享和获取开源软件包的重要平台。"ppg_common-1.14.tar.gz"就是这样一个...
标签中的"ppg"、"ppg_hr"、"ppg_matlab"、"the_signal"和"matlab_ppg"是关键主题标签,它们分别对应PPG技术、心率估算、使用MATLAB进行PPG处理、信号本身以及MATLAB中处理PPG的代码。 在压缩包的文件名列表中,只有...
接下来,代码可能会使用某种算法来检测PPG信号中的峰值,这些峰值对应于心脏的搏动,进而计算出心率。常见的峰值检测算法有阈值法、模板匹配法、导数法等。 在剧烈运动场景下,心率估算的准确性至关重要。因此,该...
标题中的"bandpass.zip_PPG_PPG信号_matlab 特征提取 信号处理_ppg特征提取_波峰"表明这是一个关于PPG(光电容积描记术)信号处理的项目,其中包含了使用MATLAB进行特征提取,特别是识别波峰的重要环节。在PPG信号...
`.whl`是一种预编译的Python软件包格式,旨在简化安装过程,使得用户能够在不依赖于构建环境的情况下快速部署和使用库。 首先,我们来看`ppg_common`这个名字,"ppg"可能是“Python编程通用”或项目特定的缩写,而...
资源分类:Python库 所属语言:Python 资源全名:ppg_common-1.39.tar.gz 资源来源:官方 安装方法:https://lanzao.blog.csdn.net/article/details/101784059
《PPG.rar:PPG_The Power——C++实现的简单游戏解析》 "PPG.rar_PPG_The Power" 是一个以C++语言编写的简单游戏,它以美国动画片《飞天小女警》(Powerpuff Girls,简称PPG)为主题,为玩家提供了一次重温经典的...
标签进一步强调了主题,"ecg_and_ppg"表示同时涉及ECG和PPG的分析,"ppg_matlab"表明使用MATLAB处理PPG数据,而"the_signal"可能指的是信号处理的一般概念。 压缩包内的文件名为"Signal",很可能包含的是原始信号...
标题中的“PPG.rar_PPG_footel7_fujitsu_thou785_单片机ppg”揭示了我们正在处理一个与富士通(Fujitsu)单片机相关的项目,具体是关于心率监测的光电容积脉搏波(PPG)功能。这个项目可能涉及到一个名为“footel7”...
《PPG.zip - PPG_The Power》是一个基于C++编程语言开发的简单游戏,它以流行的卡通《神奇女侠》(Powerpuff Girls)为主题。这款游戏可能旨在重现动画片中的角色和故事情节,为玩家提供一种互动式的娱乐体验。 在...
This_data_set_records_the_blood_glucose_and_PPG_da_glucose-PPG-data-set
workshopios_ppg:塞米纳里奥斯(Resinhas dos encontros)
标题中的"yangben1.rar_PPG_yangben1_人体_脉_脉象"表明这是一个与PPG(光体积描记法)相关的数据集,主要关注人体的脉象研究。脉象在中国传统医学中是非常重要的诊断手段,它涉及到中医对人体健康状态的判断。在这...
信道预测matlab代码袖带血压预测 该存储库托管使用两种方法根据ECG和PPG信号预测血压的代码。 使用机器学习方法进行特征提取和回归。 基于深度学习的回归。 入门: 克隆此仓库: git clone ...数据集: ...
引用来源:如果你使用这个数据集,请参考 环境 原始源是在 Matlab 2016a 中开发的。 建议使用同等或更高版本。 此应用程序使用以下 Matlab 工具箱: 下载 该应用程序可以通过 Matlab 中的内置工具下载。 如何跑步 该...
文件"Keysight_PXI_Digitizer_PPG-main"可能包含了驱动程序的安装文件、使用手册、示例代码或者配置文件,这些都是为了帮助用户顺利安装和使用Keysight PXI Digitizer与Labber的接口。在实际操作中,用户应按照文档...
标题 "Sensor_ECG_PPG_MAX86150_Dev-Board-master.zip" 提供了有关此压缩包的核心信息:它包含一个与MAX86150传感器相关的EKG(心电图)和PPG(光电容积描记法)开发板的项目。MAX86150是一款集成的心率和血氧饱和度...