openGauss内核分析(六)执行计划生成
SQL语句解析完成后被解析成Query结构,在进行优化时是以Query为单位进行的,Query的优化分为基于规则的逻辑优化(查询重写)和基于代价的物理优化(计划生成),主入口函数为subquery_planner。subquery_planner函数接收Query(查询树),返回一个Plan(计划树)。
Plan* subquery_planner(PlannerGlobal* glob, Query* parse, PlannerInfo* parent_root, bool hasRecursion,
double tuple_fraction, PlannerInfo** subroot, int options, ItstDisKey* diskeys, List* subqueryRestrictInfo)
{
PlannerInfo* root = NULL;
Plan* plan = NULL; // 返回结果
…
preprocess_const_params(root, (Node*)parse->jointree); / / 常数替换等式
…
if (parse->hasSubLinks) {
pull_up_sublinks(root); / / 提升子链接
DEBUG_QRW("After sublink pullup");
}
/* Reduce orderby clause in subquery for join */
reduce_orderby(parse, false); / / 减少 orderby
DEBUG_QRW("After order by reduce");
if (u_sess->attr.attr_sql.enable_constraint_optimization) {
removeNotNullTest(root); / / 删除 NotNullTest
DEBUG_QRW("After soft constraint removal");
}
…
if ((LAZY_AGG & u_sess->attr.attr_sql.rewrite_rule) && permit_from_rewrite_hint(root, LAZY_AGG)) {
lazyagg_main(parse); / / lazyagg 重写
DEBUG_QRW("After lazyagg");
}
…
parse->jointree = (FromExpr*)pull_up_subqueries(root, (Node*)parse->jointree); // 提升子查询
…
if (parse->setOperations) {
flatten_simple_union_all(root); //UNIONALL 优化
DEBUG_QRW("After simple union all flatten");
}
…
expand_inherited_tables(root); // 展开继承表
…
parse->targetList = (List*)preprocess_expression(root, (Node*)parse->targetList, EXPRKIND_TARGET); / / 预处理表达式
…
parse->havingQual = (Node *) newHaving; // 处理 HAVING 子句
…
reduce_outer_joins(root); // 外连接消除
…
reduce_inequality_fulljoins(root); // 全连接重写
…
plan = grouping_planner(root, tuple_fraction); // 主要的计划过程
…
return plan;
}
subquery_planner 函数由函数 standard_planner 调用 , standard_planner 函数由 exec_simple_query->pg_plan_queries->pg_plan_query->planner 函数调用 。 standard_planner 将 Query( 查询树 ) 生成规划好的语句,可用于执行器实际执行。
PlannedStmt* standard_planner(Query* parse, int cursorOptions, ParamListInfo boundParams)
{
PlannedStmt* result = NULL; // 返回结果
PlannerGlobal* glob = NULL;
double tuple_fraction;
PlannerInfo* root = NULL;
Plan* top_plan = NULL;
…
glob = makeNode(PlannerGlobal);
/* primary planning entry point (may recurse for subqueries) */
top_plan = subquery_planner(glob, parse, NULL, false, tuple_fraction, &root); // 主规划过程入口
…
/* build the PlannedStmt result */
result = makeNode(PlannedStmt); // 构造 PlannedStmt
result->commandType = parse->commandType;
result->queryId = parse->queryId;
result->uniqueSQLId = parse->uniqueSQLId;
result->hasReturning = (parse->returningList != NIL);
result->hasModifyingCTE = parse->hasModifyingCTE;
result->canSetTag = parse->canSetTag;
result->transientPlan = glob->transientPlan;
result->dependsOnRole = glob->dependsOnRole;
result->planTree = top_plan; // 执行计划
result->rtable = glob->finalrtable;
result->resultRelations = glob->resultRelations;
…
return result;
}
仍然以前文的 join 列子来说明
SELECT * FROM t1 inner JOIN t2 ON t1.c1 = t2.c1;
在 planner 函数打断点,用 gdb 查看 standard_planner 返回的 PlannedStmt (gdb) bt
#0 planner (parse=0x7fd93a410288, cursorOptions=0, boundParams=0x0) at planner.cpp:389
#1 0x0000000001936fbd in pg_plan_query (querytree=0x7fd93a410288, cursorOptions=0, boundParams=0x0, underExplain=false) at postgres.cpp:1197
#2 0x0000000001937381 in pg_plan_queries (querytrees=0x7fd939b81090, cursorOptions=0, boundParams=0x0) at postgres.cpp:1315
#3 0x000000000193a6b8 in exec_simple_query (query_string=0x7fd966ad2060 "SELECT * FROM t1 inner JOIN t2 ON t1.c1 = t2.c1;", messageType=QUERY_MESSAGE, msg=0x7fd931056210)
at postgres.cpp:2560
#4 0x0000000001947104 in PostgresMain (argc=1, argv=0x7fd93a2cf1c0, dbname=0x7fd93a2ce1f8 "postgres", username=0x7fd93a2ce1b0 "test") at postgres.cpp:8403
#5 0x0000000001890740 in BackendRun (port=0x7fd931056720) at postmaster.cpp:8053
#6 0x00000000018a00b1 in GaussDbThreadMain (arg=0x7fd97c55c5f0) at postmaster.cpp:12181
#7 0x000000000189c0de in InternalThreadFunc (args=0x7fd97c55c5f0) at postmaster.cpp:12755
#8 0x00000000024bf7d8 in ThreadStarterFunc (arg=0x7fd97c55c5e0) at gs_thread.cpp:382
#9 0x00007fd9a60cfdd5 in start_thread () from /lib64/libpthread.so.0
#10 0x00007fd9a5df8ead in clone () from /lib64/libc.so.6
(gdb) p *result
$14 = {type = T_PlannedStmt, commandType = CMD_SELECT, queryId = 0, hasReturning = false, hasModifyingCTE = false, canSetTag = true, transientPlan = false, dependsOnRole = false,
planTree = 0x7fd93a409d58, rtable = 0x7fd939b81660, …}
(gdb) p *result->planTree->lefttree
$46 = {type = T_SeqScan, plan_node_id = 2, parent_node_id = 1, exec_type = EXEC_ON_DATANODES, startup_cost = 0, total_cost = 1.03, plan_rows = 3, multiple = 1, plan_width = 8,…}
将 Q uery 规划 后得到 PlannedStmt
可以看到, Plannedstmt 与 explain 执行计划 是 一致 的
人间秘境孙觌山庄近期,有媒体刊登一篇关于孙觌山庄的文章,读之让人起游览之兴。孙觌山庄的旧址在今无锡市滨湖区马山,历史上属于武进(晋陵阳湖)县迎春乡。这里山水相依,景色十分优美。春秋战国时期极个别大
中国最后的枕水人家,鱼米之乡,丝绸之府乌镇乌镇镇,隶属于浙江省嘉兴市桐乡市,地处江浙沪金三角之地杭嘉湖平原腹地。乌镇境内水系属太湖流域,河流纵横交织,京杭大运河依镇而过。乌镇原以市河为界,分为乌青二镇,河西为乌镇,属湖州府
包拯打座开封府河南省开封市包公东湖北岸,是北宋京都官吏行政司法的衙署,被誉为天下首府。据史料记载,北宋开封府共有183任府尹,尤以包公打座南衙而驰名中外。流行当地的曲剧铡美案就发生这里。今日重建
被夸爆的宝藏围巾,LVSKI系列是懂女孩子的不论南北方,一到冬季,妖风的物理攻击和寒潮的法术攻击总能无孔不入地钻进衣服的每一处空隙,让人冷得直冒鸡皮疙瘩。即使穿得再严实,也难以顾全身体的每一处,这时候作为受冷重灾区的脖子,就
盛宴开启!卡塔尔世界杯开幕东道主首战两球完败上缴昂贵学费2022年卡塔尔世界杯正式开幕。图新华网红网时刻新闻11月21日讯(记者符洹雨)北京时间11月21日0000,万众瞩目的2022年卡塔尔世界杯足球赛正式开幕!在揭幕战中,东道主卡塔
原创枫叶人生,得失看淡点,快乐多一点人生的过程,有得有失,得失参半经商,有赚有赔事业,有起有落计划,有成有败比赛,有胜有负股票,有涨有跌成绩,有高有低地位,有上有下际遇,有好有坏。贫穷时渴望财富,孤寂时渴望爱情,年老
黑龙江牡丹江最值得去八大景点冬天的童话1。雪乡地址牡丹江市海林市大海林林业局双峰林场雪乡也叫做双峰林场,这里雪质好粘度高,冬季可见到自然形成的各种雪堆造型,包括有名的雪蘑菇。在雪乡可以滑雪玩雪圈,或者起个大早坐雪地摩托
穿城而过!金山这个绝美网红打卡地,惊艳到你了吗?亲水无须远行,美景就在身边位于金山区山阳镇的长堂河穿城而过中部拓宽段又名汇龙湖水清岸绿,景色宜人跟着小编一起去看看吧!长堂河河道长度2。44km,北接老红旗港南接老龙泉港,途经龙皓
宝藏中的宝藏山西小瑞士,惊喜不止万年冰洞和绝美高山草原若要从所有省份里选一个宝藏出来,我会选山西。除了惊喜无限的地上文物,还有不少自然秘境,忻州芦芽山就是其中之一。第一次是夏天去的,被足以媲美瑞士的山地风光惊艳,每一帧都像一幅美丽的油
河北石家庄这个宝藏县城,还是全国历史文化名城,你来过吗?这里是刘小顺的旅行和生活研究所。石家庄是河北省的省会,作为一座比较年轻的省会城市,很多人都觉得石家庄似乎少了点历史底蕴,没什么好玩的地方。可是,上次我到石家庄去旅游,当地的朋友推荐
一岁学会说话,半生学会了沉默(人生感悟)人一岁学会了说话,半生才学会闭嘴,不会说话的时候牙牙学语,会说话的时候闭嘴不言。人到中年,经过一些事,看清了世间冷暖,看淡了得失成败,不想因为不重要的事情,给自己徒增烦恼。生气1分
台积电扩大投资,筑起更高壁垒文丨晚点财经龚方毅大公司重要驻地及周边的地价房价表现通常好于一般地方。杭州深圳是这样,台南也这样全球最重要半导体公司台积电在那里建了三座晶圆厂和一座封测厂。但台积电的影响力远不止台
腾讯就是活的明白从马化腾的讲话就明白,腾讯为啥活的那么好?马化腾去年讲的一句话,现在冲上热搜,说腾讯就是一家普通公司,并不是什么基础业务,随时可以被替换。小马哥的话一冲出来,腾讯就涨了4个点,功不
00后无肉不欢?出品虎嗅商业消费与机动组作者苗正卿题图视觉中国植物蛋白食品赛道的游戏规则正在变化,如今的关键逻辑是得年轻人者,得天下。如果你不太清楚什么是植物蛋白食品,或许你听过人造肉。在抖音B站
油价调整消息今天1月15日,加油站调整后全国9295号汽油售价这调价金额涨起来还真是没完没了,在本轮油价计价已完成的9个工作日里,调价金额没有一天不是在上涨,到目前整体的涨幅已经达到320元吨,距离去年10月份创下的近5年以来的最大涨幅只有2
推荐几款炫酷的电子产品作为春节礼物送给亲朋好友送小朋友电子狗准备给小朋友送礼物,可以考虑一下这款智能机器狗!遥控,可以唱歌,可以跳舞,动作酷炫无比,能给小朋友带来无穷的快乐!盈佳智能机器狗男孩儿童玩具遥控机器人电子玩具狗121
大屏电视怎么选购?我和TCL的故事大屏电视怎么选购?以前想买巨幕电视大家通常会选择激光电视,因为两三万块钱就能买到100英寸巨幕。但是为了买大屏选激光电视,往往牺牲了我们对于画质方面的要求。激光投影
燥物2021奖项巡礼之OPPOReno7Pro岁月不居,时节如流,2021年末忽焉已至,回顾这不平凡的一年,每每想到那些让我们眼前一亮的臻品,内心便燥动不已。2021年,新潮电子将围绕燥物展开年度颁奖,就2021年发布的新品技
2022年最值得买的4大手机看看你选对了吗一分钱一分货,这不是废话,尤其是在这个一切都那么透明的时代,手机厂商不敢乱来,毕竟消费者不是傻子。所以,如果你买了手机,如果你的经济实力允许,可以直接安排价格昂贵的手机,可以给你带
贺喜了,iPhone12ProMax!256G下滑1500后,国内用户又买单手机界基本上都有着这样的共识安卓阵营喜欢在形式上做出改变,比如外观设计大像素等,而苹果手机喜欢在内核上做出改变,不喜欢五颜六色的外观,只有他自己认准了可行的改变才会付诸于行动。正因
生存冒险类游戏翼星求生好玩吗?游戏相关特色详解翼星求生好玩吗?这款开放世界的生存冒险游戏一定吸引了很多小伙伴关注吧,今天小编给大家带来翼星求生游戏特色内容介绍,感兴趣的小伙伴快来看一下吧。翼星求生游戏特色内容介绍翼星求生是一款
假面骑士revice圣刃剧场版剧透详解尤里解锁EA无敌玩家体验卡假面骑士revice和圣刃的冬季剧场版,具体的详细剧透内容,这里带来具体的解释和说明,本次的剧场版不要有什么太大的期待,依旧是老三样为主,具体的剧情剧透,这里也带来详细的解释和说明