文章详情

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

请输入下面的图形验证码

提交验证

短信预约提醒成功

PostgreSQL中create_sort_plan函数实现逻辑是什么

2024-04-02 19:55

关注

这篇文章主要讲解了“PostgreSQL中create_sort_plan函数实现逻辑是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“PostgreSQL中create_sort_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->create_projection_plan函数创建计划树,执行投影操作并通过递归的方式为子访问路径生成执行计划。create_sort_plan函数创建Sort计划节点。

//---------------------------------------------------------------- create_projection_plan


static Plan *
create_projection_plan(PlannerInfo *root, ProjectionPath *best_path, int flags)
{
    Plan       *plan;
    Plan       *subplan;
    List       *tlist;
    bool        needs_result_node = false;

    
    if (use_physical_tlist(root, &best_path->path, flags))
    {
        
        subplan = create_plan_recurse(root, best_path->subpath, 0);
        tlist = subplan->targetlist;
        if (flags & CP_LABEL_TLIST)
            apply_pathtarget_labeling_to_tlist(tlist,
                                               best_path->path.pathtarget);
    }
    else if (is_projection_capable_path(best_path->subpath))
    {
        
        subplan = create_plan_recurse(root, best_path->subpath,
                                      CP_IGNORE_TLIST);
        tlist = build_path_tlist(root, &best_path->path);
    }
    else
    {
        
        subplan = create_plan_recurse(root, best_path->subpath, 0);
        tlist = build_path_tlist(root, &best_path->path);
        needs_result_node = !tlist_same_exprs(tlist, subplan->targetlist);
    }

    
    if (!needs_result_node)
    {
        
        //不需要单独的Result节点,把tlist赋值给subplan
        plan = subplan;
        plan->targetlist = tlist;

        
        //标记估算成本
        plan->startup_cost = best_path->path.startup_cost;
        plan->total_cost = best_path->path.total_cost;
        plan->plan_rows = best_path->path.rows;
        plan->plan_width = best_path->path.pathtarget->width;
        plan->parallel_safe = best_path->path.parallel_safe;
        
    }
    else
    {
        
        //需要Result节点
        plan = (Plan *) make_result(tlist, NULL, subplan);

        copy_generic_path_info(plan, (Path *) best_path);
    }

    return plan;
}

//---------------------------------------------------------------- create_sort_plan
 
 static Sort *
 create_sort_plan(PlannerInfo *root, SortPath *best_path, int flags)
 {
     Sort       *plan;
     Plan       *subplan;
 
     
     subplan = create_plan_recurse(root, best_path->subpath,
                                   flags | CP_SMALL_TLIST);
 
     
     plan = make_sort_from_pathkeys(subplan, best_path->path.pathkeys,
                                    IS_OTHER_REL(best_path->subpath->parent) ?
                                    best_path->path.parent->relids : NULL);
 
     copy_generic_path_info(&plan->plan, (Path *) best_path);
 
     return plan;
 }


//------------------------------------------------ build_path_tlist


static List *
build_path_tlist(PlannerInfo *root, Path *path)
{
    List       *tlist = NIL;
    Index      *sortgrouprefs = path->pathtarget->sortgrouprefs;
    int         resno = 1;
    ListCell   *v;

    foreach(v, path->pathtarget->exprs)
    {
        Node       *node = (Node *) lfirst(v);
        TargetEntry *tle;

        
        if (path->param_info)
            node = replace_nestloop_params(root, node);

        tle = makeTargetEntry((Expr *) node,
                              resno,
                              NULL,
                              false);
        if (sortgrouprefs)
            tle->ressortgroupref = sortgrouprefs[resno - 1];

        tlist = lappend(tlist, tle);
        resno++;
    }
    return tlist;
}

三、跟踪分析

测试脚本如下

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,设置断点,进入create_projection_plan函数

(gdb) b create_projection_plan
Breakpoint 2 at 0x7b95a8: file createplan.c, line 1627.
(gdb) c
Continuing.

Breakpoint 2, create_projection_plan (root=0x26c1258, best_path=0x2722d00, flags=1) at createplan.c:1627
1627        bool        needs_result_node = false;

转换subpath为Plan,并确定是否需要Result节点,并且判断是否需要生成Result节点

...
(gdb) n
1642        if (use_physical_tlist(root, &best_path->path, flags))
(gdb) n
1655        else if (is_projection_capable_path(best_path->subpath))
(gdb) 
1673            subplan = create_plan_recurse(root, best_path->subpath, 0);

查看best_path&best_path->subpath变量

(gdb) p *best_path
$3 = {path = {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}, subpath = 0x2722c68, dummypp = true}
(gdb) p *(SortPath *)best_path->subpath
$16 = {path = {type = T_SortPath, pathtype = T_Sort, parent = 0x2722998, pathtarget = 0x27212d8, param_info = 0x0, 
    parallel_aware = false, parallel_safe = true, parallel_workers = 0, rows = 100000, startup_cost = 20070.931487218411, 
    total_cost = 20320.931487218411, pathkeys = 0x26cfe98}, subpath = 0x2721e60}

创建subpath(SortPath)的执行计划

(gdb) step
create_plan_recurse (root=0x26c1258, best_path=0x2722c68, flags=0) at createplan.c:364
364     check_stack_depth();
(gdb) n
366     switch (best_path->pathtype)
(gdb) 
447             plan = (Plan *) create_sort_plan(root,

进入create_sort_plan

(gdb) step
create_sort_plan (root=0x26c1258, best_path=0x2722c68, flags=0) at createplan.c:1759
1759        subplan = create_plan_recurse(root, best_path->subpath,

SortPath的subpath是HashPath

(gdb) p best_path->subpath->type
$17 = T_HashPath
(gdb) p *(HashPath *)best_path->subpath
$18 = {jpath = {path = {type = T_HashPath, pathtype = T_HashJoin, parent = 0x27210c0, pathtarget = 0x27212d8, 
      param_info = 0x0, parallel_aware = false, parallel_safe = true, parallel_workers = 0, rows = 100000, 
      startup_cost = 3754, total_cost = 8689.6112499999999, pathkeys = 0x0}, jointype = JOIN_INNER, inner_unique = true, 
    outerjoinpath = 0x2720f68, innerjoinpath = 0x26d0598, joinrestrictinfo = 0x2722068}, path_hashclauses = 0x27223c0, 
  num_batches = 1, inner_rows_total = 10000}

完成SortPath执行计划的构建

(gdb) 
1774        return plan;
(gdb) 
1775    }
(gdb) p *plan
$20 = {plan = {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 = 0x2723208, qual = 0x0, 
    lefttree = 0x27243d0, righttree = 0x0, initPlan = 0x0, extParam = 0x0, allParam = 0x0}, numCols = 1, 
  sortColIdx = 0x27222a0, sortOperators = 0x2724468, collations = 0x2724488, nullsFirst = 0x27244a8}

回到上一层

(gdb) n
create_plan_recurse (root=0x26c1258, best_path=0x2722c68, flags=0) at createplan.c:450
450             break;

回到create_projection_plan函数

(gdb) n
504     return plan;
(gdb) 
505 }
(gdb) 
create_projection_plan (root=0x26c1258, best_path=0x2722d00, flags=1) at createplan.c:1674
1674            tlist = build_path_tlist(root, &best_path->path);

执行完毕,返回create_plan,结果,最外层的Plan为Sort

(gdb) 
1708        return plan;
(gdb) 
1709    }
(gdb) p *plan
$22 = {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) n
create_plan_recurse (root=0x26c1258, best_path=0x2722d00, flags=1) at createplan.c:504
504     return plan;
(gdb) p *plan
$23 = {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) n
505 }
(gdb) 
create_plan (root=0x26c1258, best_path=0x2722d00) at createplan.c:329
329     if (!IsA(plan, ModifyTable))

感谢各位的阅读,以上就是“PostgreSQL中create_sort_plan函数实现逻辑是什么”的内容了,经过本文的学习后,相信大家对PostgreSQL中create_sort_plan函数实现逻辑是什么这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!

阅读原文内容投诉

免责声明:

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

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

软考中级精品资料免费领

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

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

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

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

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

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

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