本篇内容主要讲解“PostgreSQL中create_plan的实现逻辑是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“PostgreSQL中create_plan的实现逻辑是什么”吧!
一、数据结构
Plan
所有计划节点通过将Plan结构作为第一个字段从Plan结构“派生”。这确保了在将节点转换为计划节点时,一切都能正常工作。(在执行器中以通用方式传递时,节点指针经常被转换为Plan *)
typedef struct Plan
{
NodeTag type;//节点类型
Cost startup_cost;
Cost total_cost;
double plan_rows;
int plan_width;
bool parallel_aware;
bool parallel_safe;
int plan_node_id;
List *targetlist;
List *qual;
struct Plan *lefttree;
struct Plan *righttree;
List *initPlan;
Bitmapset *extParam;
Bitmapset *allParam;
} Plan;
二、源码解读
create_plan调用create_plan_recurse函数,递归遍历访问路径,相应的创建计划(Plan)节点。
Plan *
create_plan(PlannerInfo *root, Path *best_path)
{
Plan *plan;
//plan_params在当前查询层次上不应使用(值为NULL)
Assert(root->plan_params == NIL);
//初始化该模块中优化器信息的私有工作空间
root->curOuterRels = NULL;
root->curOuterParams = NIL;
//递归处理计划树(tlist参数设置为CP_EXACT_TLIST)
plan = create_plan_recurse(root, best_path, CP_EXACT_TLIST);
if (!IsA(plan, ModifyTable))
apply_tlist_labeling(plan->targetlist, root->processed_tlist);//非ModifyTable
SS_attach_initplans(root, plan);
//检查已经为计划节点参数NestLoopParams赋值
if (root->curOuterParams != NIL)
elog(ERROR, "failed to assign all NestLoopParams to plan nodes");
root->plan_params = NIL;
return plan;
}
//------------------------------------------------------------------------ create_plan_recurse
static Plan *
create_plan_recurse(PlannerInfo *root, Path *best_path, int flags)
{
Plan *plan;
//确保堆栈不会溢出
check_stack_depth();
switch (best_path->pathtype)//根据路径类型,执行相应的处理
{
case T_SeqScan://顺序扫描
case T_SampleScan://采样扫描
case T_IndexScan://索引扫描
case T_IndexOnlyScan://索引快速扫描
case T_BitmapHeapScan://位图堆扫描
case T_TidScan://TID扫描
case T_SubqueryScan://子查询扫描
case T_FunctionScan://函数扫描
case T_TableFuncScan://表函数扫描
case T_ValuesScan://Values扫描
case T_CteScan://CTE扫描
case T_WorkTableScan://WorkTable扫描
case T_NamedTuplestoreScan://NamedTuplestore扫描
case T_ForeignScan://外表扫描
case T_CustomScan://自定义扫描
plan = create_scan_plan(root, best_path, flags);//扫描计划
break;
case T_HashJoin://Hash连接
case T_MergeJoin://合并连接
case T_NestLoop://内嵌循环连接
plan = create_join_plan(root,
(JoinPath *) best_path);//连接结合
break;
case T_Append://追加(集合)
plan = create_append_plan(root,
(AppendPath *) best_path);//追加(集合并)计划
break;
case T_MergeAppend://合并
plan = create_merge_append_plan(root,
(MergeAppendPath *) best_path);
break;
case T_Result://投影操作
if (IsA(best_path, ProjectionPath))
{
plan = create_projection_plan(root,
(ProjectionPath *) best_path,
flags);
}
else if (IsA(best_path, MinMaxAggPath))
{
plan = (Plan *) create_minmaxagg_plan(root,
(MinMaxAggPath *) best_path);
}
else
{
Assert(IsA(best_path, ResultPath));
plan = (Plan *) create_result_plan(root,
(ResultPath *) best_path);
}
break;
case T_ProjectSet://投影集合操作
plan = (Plan *) create_project_set_plan(root,
(ProjectSetPath *) best_path);
break;
case T_Material://物化
plan = (Plan *) create_material_plan(root,
(MaterialPath *) best_path,
flags);
break;
case T_Unique://唯一处理
if (IsA(best_path, UpperUniquePath))
{
plan = (Plan *) create_upper_unique_plan(root,
(UpperUniquePath *) best_path,
flags);
}
else
{
Assert(IsA(best_path, UniquePath));
plan = create_unique_plan(root,
(UniquePath *) best_path,
flags);
}
break;
case T_Gather://汇总收集
plan = (Plan *) create_gather_plan(root,
(GatherPath *) best_path);
break;
case T_Sort://排序
plan = (Plan *) create_sort_plan(root,
(SortPath *) best_path,
flags);
break;
case T_Group://分组
plan = (Plan *) create_group_plan(root,
(GroupPath *) best_path);
break;
case T_Agg://聚集计算
if (IsA(best_path, GroupingSetsPath))
plan = create_groupingsets_plan(root,
(GroupingSetsPath *) best_path);
else
{
Assert(IsA(best_path, AggPath));
plan = (Plan *) create_agg_plan(root,
(AggPath *) best_path);
}
break;
case T_WindowAgg://窗口函数
plan = (Plan *) create_windowagg_plan(root,
(WindowAggPath *) best_path);
break;
case T_SetOp://集合操作
plan = (Plan *) create_setop_plan(root,
(SetOpPath *) best_path,
flags);
break;
case T_RecursiveUnion://递归UNION
plan = (Plan *) create_recursiveunion_plan(root,
(RecursiveUnionPath *) best_path);
break;
case T_LockRows://锁定(for update)
plan = (Plan *) create_lockrows_plan(root,
(LockRowsPath *) best_path,
flags);
break;
case T_ModifyTable://更新
plan = (Plan *) create_modifytable_plan(root,
(ModifyTablePath *) best_path);
break;
case T_Limit://限制操作
plan = (Plan *) create_limit_plan(root,
(LimitPath *) best_path,
flags);
break;
case T_GatherMerge://收集合并
plan = (Plan *) create_gather_merge_plan(root,
(GatherMergePath *) best_path);
break;
default://其他非法类型
elog(ERROR, "unrecognized node type: %d",
(int) best_path->pathtype);
plan = NULL;
break;
}
return plan;
}
//------------------------------------------------------------------------ apply_tlist_labeling
void
apply_tlist_labeling(List *dest_tlist, List *src_tlist)
{
ListCell *ld,
*ls;
Assert(list_length(dest_tlist) == list_length(src_tlist));
forboth(ld, dest_tlist, ls, src_tlist)
{
TargetEntry *dest_tle = (TargetEntry *) lfirst(ld);
TargetEntry *src_tle = (TargetEntry *) lfirst(ls);
Assert(dest_tle->resno == src_tle->resno);
dest_tle->resname = src_tle->resname;
dest_tle->ressortgroupref = src_tle->ressortgroupref;
dest_tle->resorigtbl = src_tle->resorigtbl;
dest_tle->resorigcol = src_tle->resorigcol;
dest_tle->resjunk = src_tle->resjunk;
}
}
//------------------------------------------------------------------------ apply_tlist_labeling
void
SS_attach_initplans(PlannerInfo *root, Plan *plan)
{
plan->initPlan = root->init_plans;
}
三、跟踪分析
测试脚本如下
testdb=# explain select dw.*,grjf.grbh,grjf.xm,grjf.ny,grjf.je
testdb-# from t_dwxx dw,lateral (select gr.grbh,gr.xm,jf.ny,jf.je
testdb(# from t_grxx gr inner join t_jfxx jf
testdb(# on gr.dwbh = dw.dwbh
testdb(# and gr.grbh = jf.grbh) grjf
testdb-# order by dw.dwbh;
QUERY PLAN
------------------------------------------------------------------------------------------
Sort (cost=20070.93..20320.93 rows=100000 width=47)
Sort Key: dw.dwbh
-> Hash Join (cost=3754.00..8689.61 rows=100000 width=47)
Hash Cond: ((gr.dwbh)::text = (dw.dwbh)::text)
-> Hash Join (cost=3465.00..8138.00 rows=100000 width=31)
Hash Cond: ((jf.grbh)::text = (gr.grbh)::text)
-> Seq Scan on t_jfxx jf (cost=0.00..1637.00 rows=100000 width=20)
-> Hash (cost=1726.00..1726.00 rows=100000 width=16)
-> Seq Scan on t_grxx gr (cost=0.00..1726.00 rows=100000 width=16)
-> Hash (cost=164.00..164.00 rows=10000 width=20)
-> Seq Scan on t_dwxx dw (cost=0.00..164.00 rows=10000 width=20)
(11 rows)
启动gdb,设置断点,进入
(gdb) info break
Num Type Disp Enb Address What
2 breakpoint keep y 0x00000000007b76c1 in create_plan at createplan.c:313
(gdb) c
Continuing.
Breakpoint 2, create_plan (root=0x26c1258, best_path=0x2722d00) at createplan.c:313
313 Assert(root->plan_params == NIL);
进入create_plan_recurse函数
313 Assert(root->plan_params == NIL);
(gdb) n
316 root->curOuterRels = NULL;
(gdb)
317 root->curOuterParams = NIL;
(gdb)
320 plan = create_plan_recurse(root, best_path, CP_EXACT_TLIST);
(gdb) step
create_plan_recurse (root=0x26c1258, best_path=0x2722d00, flags=1) at createplan.c:364
364 check_stack_depth();
根据访问路径类型(T_ProjectionPath)选择处理分支
(gdb) p *best_path
$1 = {type = T_ProjectionPath, pathtype = T_Result, parent = 0x2722998, pathtarget = 0x27226f8, param_info = 0x0,
parallel_aware = false, parallel_safe = true, parallel_workers = 0, rows = 100000, startup_cost = 20070.931487218411,
total_cost = 20320.931487218411, pathkeys = 0x26cfe98}
调用create_projection_plan函数
(gdb) n
400 if (IsA(best_path, ProjectionPath))
(gdb)
402 plan = create_projection_plan(root,
创建相应的Plan(T_Sort,存在左右子树),下一节将详细解释create_projection_plan函数
(gdb)
504 return plan;
(gdb) p *plan
$1 = {type = T_Sort, startup_cost = 20070.931487218411, total_cost = 20320.931487218411, plan_rows = 100000,
plan_width = 47, parallel_aware = false, parallel_safe = true, plan_node_id = 0, targetlist = 0x2724548, qual = 0x0,
lefttree = 0x27243d0, righttree = 0x0, initPlan = 0x0, extParam = 0x0, allParam = 0x0}
执行返回
(gdb)
create_plan (root=0x270f9c8, best_path=0x2722d00) at createplan.c:329
329 if (!IsA(plan, ModifyTable))
(gdb)
330 apply_tlist_labeling(plan->targetlist, root->processed_tlist);
(gdb)
339 SS_attach_initplans(root, plan);
(gdb)
342 if (root->curOuterParams != NIL)
(gdb)
349 root->plan_params = NIL;
(gdb)
351 return plan;
到此,相信大家对“PostgreSQL中create_plan的实现逻辑是什么”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!