文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

PostgreSQL中create_plan的实现逻辑是什么

2024-04-02 19:55

关注

本篇内容主要讲解“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的实现逻辑是什么”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-数据库
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯