文章详情

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

请输入下面的图形验证码

提交验证

短信预约提醒成功

PostgreSQL如何为append relation构建访问路径

2024-04-02 19:55

关注

这篇文章给大家分享的是有关PostgreSQL如何为append relation构建访问路径的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。

一、数据结构

AppendRelInfo
当我们将可继承表(分区表)或UNION-ALL子查询展开为“追加关系”(本质上是子RTE的链表)时,为每个子RTE构建一个AppendRelInfo。



typedef struct AppendRelInfo
{
    NodeTag     type;

    
    Index       parent_relid;   
    Index       child_relid;    

    
    Oid         parent_reltype; 
    Oid         child_reltype;  

    
    //child's Vars中的表达式
    List       *translated_vars;    

    
    Oid         parent_reloid;  
} AppendRelInfo;

RelOptInfo
规划器/优化器使用的关系信息结构体
参见PostgreSQL 源码解读(99)- 分区表#5(数据查询路由#2-RelOptInfo数据结构)

二、源码解读

set_rel_pathlist函数为基础关系构建访问路径.

//是否DUMMY访问路径
#define IS_DUMMY_PATH(p) \
    (IsA((p), AppendPath) && ((AppendPath *) (p))->subpaths == NIL)


//已被证明为空的关系会含有一个虚拟dummy的访问路径
#define IS_DUMMY_REL(r) \
    ((r)->cheapest_total_path != NULL && \
     IS_DUMMY_PATH((r)->cheapest_total_path))



static void
set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
                 Index rti, RangeTblEntry *rte)
{
    if (IS_DUMMY_REL(rel))
    {
        
        //不需要做任何处理
    }
    else if (rte->inh)
    {
        
        //append relation,调用set_append_rel_pathlist处理
        set_append_rel_pathlist(root, rel, rti, rte);
    }
    else
    {//其他类型的关系
        switch (rel->rtekind)
        {
            case RTE_RELATION://基础关系
                if (rte->relkind == RELKIND_FOREIGN_TABLE)
                {
                    
                    //外部表
                    set_foreign_pathlist(root, rel, rte);
                }
                else if (rte->tablesample != NULL)
                {
                    
                    //数据表采样
                    set_tablesample_rel_pathlist(root, rel, rte);
                }
                else
                {
                    
                    //常规关系
                    set_plain_rel_pathlist(root, rel, rte);
                }
                break;
            case RTE_SUBQUERY:
                
                //子查询
                break;
            case RTE_FUNCTION:
                
                set_function_pathlist(root, rel, rte);
                break;
            case RTE_TABLEFUNC:
                
                set_tablefunc_pathlist(root, rel, rte);
                break;
            case RTE_VALUES:
                
                set_values_pathlist(root, rel, rte);
                break;
            case RTE_CTE:
                
                break;
            case RTE_NAMEDTUPLESTORE:
                
                break;
            default:
                elog(ERROR, "unexpected rtekind: %d", (int) rel->rtekind);
                break;
        }
    }

    
    if (rel->reloptkind == RELOPT_BASEREL &&
        bms_membership(root->all_baserels) != BMS_SINGLETON)
        generate_gather_paths(root, rel, false);

    
    if (set_rel_pathlist_hook)
        (*set_rel_pathlist_hook) (root, rel, rti, rte);

    
    //为rel找到成本最低的访问路径
    set_cheapest(rel);

#ifdef OPTIMIZER_DEBUG
    debug_print_rel(root, rel);
#endif
}


 
static void
set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
                        Index rti, RangeTblEntry *rte)
{
    int         parentRTindex = rti;
    List       *live_childrels = NIL;
    ListCell   *l;

    
    foreach(l, root->append_rel_list)//遍历链表
    {
        AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);//获取AppendRelInfo
        int         childRTindex;
        RangeTblEntry *childRTE;
        RelOptInfo *childrel;

        
        //append_rel_list含有所有的append relations,忽略其他的rels
        if (appinfo->parent_relid != parentRTindex)
            continue;

        
        //重新定位子RTE和RelOptInfo
        childRTindex = appinfo->child_relid;
        childRTE = root->simple_rte_array[childRTindex];
        childrel = root->simple_rel_array[childRTindex];

        
        if (!rel->consider_parallel)
            childrel->consider_parallel = false;

        
        set_rel_pathlist(root, childrel, childRTindex, childRTE);

        
        if (IS_DUMMY_REL(childrel))
            continue;

        
        //
        if (rel->part_scheme)
            rel->partitioned_child_rels =
                list_concat(rel->partitioned_child_rels,
                            list_copy(childrel->partitioned_child_rels));

        
        live_childrels = lappend(live_childrels, childrel);
    }

    
    //添加访问路径到append relation中
    add_paths_to_append_rel(root, rel, live_childrels);
}



void
add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
                        List *live_childrels)
{
    List       *subpaths = NIL;
    bool        subpaths_valid = true;
    List       *partial_subpaths = NIL;
    List       *pa_partial_subpaths = NIL;
    List       *pa_nonpartial_subpaths = NIL;
    bool        partial_subpaths_valid = true;
    bool        pa_subpaths_valid;
    List       *all_child_pathkeys = NIL;
    List       *all_child_outers = NIL;
    ListCell   *l;
    List       *partitioned_rels = NIL;
    double      partial_rows = -1;

    
    //如可以,考虑并行append
    pa_subpaths_valid = enable_parallel_append && rel->consider_parallel;

    
    if (rel->part_scheme != NULL)
    {
        if (IS_SIMPLE_REL(rel))
            partitioned_rels = list_make1(rel->partitioned_child_rels);
        else if (IS_JOIN_REL(rel))
        {
            int         relid = -1;
            List       *partrels = NIL;

            
            while ((relid = bms_next_member(rel->relids, relid)) >= 0)
            {
                RelOptInfo *component;

                Assert(relid >= 1 && relid < root->simple_rel_array_size);
                component = root->simple_rel_array[relid];
                Assert(component->part_scheme != NULL);
                Assert(list_length(component->partitioned_child_rels) >= 1);
                partrels =
                    list_concat(partrels,
                                list_copy(component->partitioned_child_rels));
            }

            partitioned_rels = list_make1(partrels);
        }

        Assert(list_length(partitioned_rels) >= 1);
    }

    
    foreach(l, live_childrels)//遍历
    {
        RelOptInfo *childrel = lfirst(l);
        ListCell   *lcp;
        Path       *cheapest_partial_path = NULL;

        
        if (rel->rtekind == RTE_SUBQUERY && childrel->partitioned_child_rels != NIL)
            partitioned_rels = lappend(partitioned_rels,
                                       childrel->partitioned_child_rels);

        
        if (childrel->pathlist != NIL &&
            childrel->cheapest_total_path->param_info == NULL)
            accumulate_append_subpath(childrel->cheapest_total_path,
                                      &subpaths, NULL);
        else
            subpaths_valid = false;

        
        //同样的思路,处理并行处理中的部分计划
        if (childrel->partial_pathlist != NIL)
        {
            cheapest_partial_path = linitial(childrel->partial_pathlist);
            accumulate_append_subpath(cheapest_partial_path,
                                      &partial_subpaths, NULL);
        }
        else
            partial_subpaths_valid = false;

        
        if (pa_subpaths_valid)
        {
            Path       *nppath = NULL;

            nppath =
                get_cheapest_parallel_safe_total_inner(childrel->pathlist);

            if (cheapest_partial_path == NULL && nppath == NULL)
            {
                
                //不是部分路径,也不是并行安全的路径,跳过
                pa_subpaths_valid = false;
            }
            else if (nppath == NULL ||
                     (cheapest_partial_path != NULL &&
                      cheapest_partial_path->total_cost < nppath->total_cost))
            {
                
                //部分路径成本更低或者是唯一的选项
                Assert(cheapest_partial_path != NULL);
                accumulate_append_subpath(cheapest_partial_path,
                                          &pa_partial_subpaths,
                                          &pa_nonpartial_subpaths);

            }
            else
            {
                
                accumulate_append_subpath(nppath,
                                          &pa_nonpartial_subpaths,
                                          NULL);
            }
        }

        
        foreach(lcp, childrel->pathlist)
        {
            Path       *childpath = (Path *) lfirst(lcp);
            List       *childkeys = childpath->pathkeys;
            Relids      childouter = PATH_REQ_OUTER(childpath);

            
            //未排序的访问路径,不需要分发到路径键链表中
            if (childkeys != NIL)
            {
                ListCell   *lpk;
                bool        found = false;

                
                foreach(lpk, all_child_pathkeys)
                {
                    List       *existing_pathkeys = (List *) lfirst(lpk);

                    if (compare_pathkeys(existing_pathkeys,
                                         childkeys) == PATHKEYS_EQUAL)
                    {
                        found = true;
                        break;
                    }
                }
                if (!found)
                {
                    
                    all_child_pathkeys = lappend(all_child_pathkeys,
                                                 childkeys);
                }
            }

            
            //非参数访问路径无需分发到参数化集合链表中
            if (childouter)
            {
                ListCell   *lco;
                bool        found = false;

                
                foreach(lco, all_child_outers)
                {
                    Relids      existing_outers = (Relids) lfirst(lco);

                    if (bms_equal(existing_outers, childouter))
                    {
                        found = true;
                        break;
                    }
                }
                if (!found)
                {
                    
                    all_child_outers = lappend(all_child_outers,
                                               childouter);
                }
            }
        }
    }

    
    if (subpaths_valid)
        add_path(rel, (Path *) create_append_path(root, rel, subpaths, NIL,
                                                  NULL, 0, false,
                                                  partitioned_rels, -1));

    
    if (partial_subpaths_valid)
    {
        AppendPath *appendpath;
        ListCell   *lc;
        int         parallel_workers = 0;

        
        //为子访问路径寻找最多数量的wokers
        foreach(lc, partial_subpaths)
        {
            Path       *path = lfirst(lc);

            parallel_workers = Max(parallel_workers, path->parallel_workers);
        }
        Assert(parallel_workers > 0);

        
        if (enable_parallel_append)
        {
            parallel_workers = Max(parallel_workers,
                                   fls(list_length(live_childrels)));//上限值
            parallel_workers = Min(parallel_workers,
                                   max_parallel_workers_per_gather);//下限值
        }
        Assert(parallel_workers > 0);

        
        //生成并行部分append访问路径
        appendpath = create_append_path(root, rel, NIL, partial_subpaths,
                                        NULL, parallel_workers,
                                        enable_parallel_append,
                                        partitioned_rels, -1);

        
        partial_rows = appendpath->path.rows;

        
        //添加路径
        add_partial_path(rel, (Path *) appendpath);
    }

    
    if (pa_subpaths_valid && pa_nonpartial_subpaths != NIL)
    {
        AppendPath *appendpath;
        ListCell   *lc;
        int         parallel_workers = 0;

        
        foreach(lc, pa_partial_subpaths)
        {
            Path       *path = lfirst(lc);

            parallel_workers = Max(parallel_workers, path->parallel_workers);
        }

        
        parallel_workers = Max(parallel_workers,
                               fls(list_length(live_childrels)));
        parallel_workers = Min(parallel_workers,
                               max_parallel_workers_per_gather);
        Assert(parallel_workers > 0);

        appendpath = create_append_path(root, rel, pa_nonpartial_subpaths,
                                        pa_partial_subpaths,
                                        NULL, parallel_workers, true,
                                        partitioned_rels, partial_rows);
        add_partial_path(rel, (Path *) appendpath);
    }

    
    if (subpaths_valid)
        generate_mergeappend_paths(root, rel, live_childrels,
                                   all_child_pathkeys,
                                   partitioned_rels);

    
    foreach(l, all_child_outers)
    {
        Relids      required_outer = (Relids) lfirst(l);
        ListCell   *lcr;

        
        subpaths = NIL;
        subpaths_valid = true;
        foreach(lcr, live_childrels)
        {
            RelOptInfo *childrel = (RelOptInfo *) lfirst(lcr);
            Path       *subpath;

            if (childrel->pathlist == NIL)
            {
                
                subpaths_valid = false;
                break;
            }

            subpath = get_cheapest_parameterized_child_path(root,
                                                            childrel,
                                                            required_outer);
            if (subpath == NULL)
            {
                
                subpaths_valid = false;
                break;
            }
            accumulate_append_subpath(subpath, &subpaths, NULL);
        }

        if (subpaths_valid)
            add_path(rel, (Path *)
                     create_append_path(root, rel, subpaths, NIL,
                                        required_outer, 0, false,
                                        partitioned_rels, -1));
    }
}

三、跟踪分析

测试脚本如下

testdb=# explain verbose select * from t_hash_partition where c1 = 1 OR c1 = 2;
                                     QUERY PLAN                                      
-------------------------------------------------------------------------------------
 Append  (cost=0.00..30.53 rows=6 width=200)
   ->  Seq Scan on public.t_hash_partition_1  (cost=0.00..15.25 rows=3 width=200)
         Output: t_hash_partition_1.c1, t_hash_partition_1.c2, t_hash_partition_1.c3
         Filter: ((t_hash_partition_1.c1 = 1) OR (t_hash_partition_1.c1 = 2))
   ->  Seq Scan on public.t_hash_partition_3  (cost=0.00..15.25 rows=3 width=200)
         Output: t_hash_partition_3.c1, t_hash_partition_3.c2, t_hash_partition_3.c3
         Filter: ((t_hash_partition_3.c1 = 1) OR (t_hash_partition_3.c1 = 2))
(7 rows)

启动gdb,设置断点

(gdb) b set_rel_pathlist
Breakpoint 1 at 0x796823: file allpaths.c, line 425.
(gdb) c
Continuing.

Breakpoint 1, set_rel_pathlist (root=0x1f1e400, rel=0x1efaba0, rti=1, rte=0x1efa3d0) at allpaths.c:425
425     if (IS_DUMMY_REL(rel))
(gdb)

通过rte->inh判断是否分区表或者UNION ALL

(gdb) p rte->inh
$1 = true
(gdb)

进入set_append_rel_pathlist函数

(gdb) n
429     else if (rte->inh)
(gdb) 
432         set_append_rel_pathlist(root, rel, rti, rte);
(gdb) step
set_append_rel_pathlist (root=0x1f1e400, rel=0x1efaba0, rti=1, rte=0x1efa3d0) at allpaths.c:1296
1296        int         parentRTindex = rti;

遍历子关系

(gdb) n
1297        List       *live_childrels = NIL;
(gdb) 
1304        foreach(l, root->append_rel_list)
(gdb) 
(gdb) p *root->append_rel_list
$2 = {type = T_List, length = 6, head = 0x1fc1f98, tail = 0x1fc2ae8}

获取AppendRelInfo,判断父关系是否正在处理的父关系

(gdb) n
1306            AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);
(gdb) 
1312            if (appinfo->parent_relid != parentRTindex)
(gdb) p *appinfo
$3 = {type = T_AppendRelInfo, parent_relid = 1, child_relid = 3, parent_reltype = 16988, child_reltype = 16991, 
  translated_vars = 0x1fc1e60, parent_reloid = 16986}
(gdb)

获取子关系的相关信息,递归调用set_rel_pathlist

(gdb) n
1316            childRTindex = appinfo->child_relid;
(gdb) 
1317            childRTE = root->simple_rte_array[childRTindex];
(gdb) 
1318            childrel = root->simple_rel_array[childRTindex];
(gdb) 
1326            if (!rel->consider_parallel)
(gdb) 
1332            set_rel_pathlist(root, childrel, childRTindex, childRTE);
(gdb) 
(gdb) 

Breakpoint 1, set_rel_pathlist (root=0x1f1e400, rel=0x1f1c8a0, rti=3, rte=0x1efa658) at allpaths.c:425
425     if (IS_DUMMY_REL(rel))
(gdb) finish
Run till exit from #0  set_rel_pathlist (root=0x1f1e400, rel=0x1f1c8a0, rti=3, rte=0x1efa658) at allpaths.c:425
set_append_rel_pathlist (root=0x1f1e400, rel=0x1efaba0, rti=1, rte=0x1efa3d0) at allpaths.c:1337

如为虚拟关系,则忽略之

1337            if (IS_DUMMY_REL(childrel))

该子关系不是虚拟关系,继续处理,加入到rel->partitioned_child_rels和live_childrels链表中

(gdb) n
1341            if (rel->part_scheme)
(gdb) 
1344                                list_copy(childrel->partitioned_child_rels));
(gdb) 
1343                    list_concat(rel->partitioned_child_rels,
(gdb) 
1342                rel->partitioned_child_rels =
(gdb) 
1349            live_childrels = lappend(live_childrels, childrel);
(gdb) p *rel->partitioned_child_rels
$4 = {type = T_IntList, length = 1, head = 0x1fc4d78, tail = 0x1fc4d78}
(gdb) p rel->partitioned_child_rels->head->data.int_value
$6 = 1
(gdb) 
(gdb) n
1304        foreach(l, root->append_rel_list)
(gdb) p live_childrels
$7 = (List *) 0x1fd0a60
(gdb) p *live_childrels
$8 = {type = T_List, length = 1, head = 0x1fd0a38, tail = 0x1fd0a38}
(gdb) p *(Node *)live_childrels->head->data.ptr_value
$9 = {type = T_RelOptInfo}
(gdb) p *(RelOptInfo *)live_childrels->head->data.ptr_value
$10 = {type = T_RelOptInfo, reloptkind = RELOPT_OTHER_MEMBER_REL, relids = 0x1fc3590, rows = 3, consider_startup = false, 
  consider_param_startup = false, consider_parallel = true, reltarget = 0x1fc35b0, pathlist = 0x1fd0940, ppilist = 0x0, 
  partial_pathlist = 0x1fd09a0, cheapest_startup_path = 0x1fc44f8, cheapest_total_path = 0x1fc44f8, 
  cheapest_unique_path = 0x0, cheapest_parameterized_paths = 0x1fd0a00, direct_lateral_relids = 0x0, lateral_relids = 0x0, 
  relid = 3, reltablespace = 0, rtekind = RTE_RELATION, min_attr = -7, max_attr = 3, attr_needed = 0x1fc2e38, 
  attr_widths = 0x1fc3628, lateral_vars = 0x0, lateral_referencers = 0x0, indexlist = 0x0, statlist = 0x0, pages = 10, 
  tuples = 350, allvisfrac = 0, subroot = 0x0, subplan_params = 0x0, rel_parallel_workers = -1, serverid = 0, userid = 0, 
  useridiscurrent = false, fdwroutine = 0x0, fdw_private = 0x0, unique_for_rels = 0x0, non_unique_for_rels = 0x0, 
  baserestrictinfo = 0x1fc68d8, baserestrictcost = {startup = 0, per_tuple = 0.0050000000000000001}, 
  baserestrict_min_security = 0, joininfo = 0x0, has_eclass_joins = false, consider_partitionwise_join = false, 
  top_parent_relids = 0x1fc3608, part_scheme = 0x0, nparts = 0, boundinfo = 0x0, partition_qual = 0x0, part_rels = 0x0, 
  partexprs = 0x0, nullable_partexprs = 0x0, partitioned_child_rels = 0x0}

对于虚拟子关系(上一节介绍的被裁剪的分区),直接跳过

(gdb) n
1306            AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);
(gdb) 
1312            if (appinfo->parent_relid != parentRTindex)
(gdb) 
1316            childRTindex = appinfo->child_relid;
(gdb) 
1317            childRTE = root->simple_rte_array[childRTindex];
(gdb) 
1318            childrel = root->simple_rel_array[childRTindex];
(gdb) 
1326            if (!rel->consider_parallel)
(gdb) 
1332            set_rel_pathlist(root, childrel, childRTindex, childRTE);
(gdb) 
1337            if (IS_DUMMY_REL(childrel))
(gdb) 
1338                continue;

设置断点,进入add_paths_to_append_rel函数

(gdb) b add_paths_to_append_rel
Breakpoint 2 at 0x797d88: file allpaths.c, line 1372.
(gdb) c
Continuing.

Breakpoint 2, add_paths_to_append_rel (root=0x1f1cdb8, rel=0x1fc1800, live_childrels=0x1fcfb10) at allpaths.c:1372
1372        List       *subpaths = NIL;
(gdb)

输入参数,其中rel是父关系,live_childrels是经裁剪后仍存活的分区(子关系)

(gdb) n
1373        bool        subpaths_valid = true;
(gdb) p *rel
$11 = {type = T_RelOptInfo, reloptkind = RELOPT_BASEREL, relids = 0x1fc1a18, rows = 6, consider_startup = false, 
  consider_param_startup = false, consider_parallel = true, reltarget = 0x1fc1a38, pathlist = 0x0, ppilist = 0x0, 
  partial_pathlist = 0x0, cheapest_startup_path = 0x0, cheapest_total_path = 0x0, cheapest_unique_path = 0x0, 
  cheapest_parameterized_paths = 0x0, direct_lateral_relids = 0x0, lateral_relids = 0x0, relid = 1, reltablespace = 0, 
  rtekind = RTE_RELATION, min_attr = -7, max_attr = 3, attr_needed = 0x1fc1a90, attr_widths = 0x1fc1b28, 
  lateral_vars = 0x0, lateral_referencers = 0x0, indexlist = 0x0, statlist = 0x0, pages = 0, tuples = 6, allvisfrac = 0, 
  subroot = 0x0, subplan_params = 0x0, rel_parallel_workers = -1, serverid = 0, userid = 0, useridiscurrent = false, 
  fdwroutine = 0x0, fdw_private = 0x0, unique_for_rels = 0x0, non_unique_for_rels = 0x0, baserestrictinfo = 0x1fc3e20, 
  baserestrictcost = {startup = 0, per_tuple = 0}, baserestrict_min_security = 0, joininfo = 0x0, has_eclass_joins = false, 
  consider_partitionwise_join = false, top_parent_relids = 0x0, part_scheme = 0x1fc1b80, nparts = 6, boundinfo = 0x1fc1d30, 
  partition_qual = 0x0, part_rels = 0x1fc2000, partexprs = 0x1fc1f08, nullable_partexprs = 0x1fc1fe0, 
  partitioned_child_rels = 0x1fc3ea0}

初始化变量

(gdb) n
1374        List       *partial_subpaths = NIL;
(gdb) 
1375        List       *pa_partial_subpaths = NIL;
(gdb) 
1376        List       *pa_nonpartial_subpaths = NIL;
(gdb) 
1377        bool        partial_subpaths_valid = true;
(gdb) 
1379        List       *all_child_pathkeys = NIL;
(gdb) 
1380        List       *all_child_outers = NIL;
(gdb) 
1382        List       *partitioned_rels = NIL;
(gdb) 
1383        double      partial_rows = -1;
(gdb) 
1386        pa_subpaths_valid = enable_parallel_append && rel->consider_parallel;
(gdb) 
1404        if (rel->part_scheme != NULL)
(gdb) p pa_subpaths_valid
$17 = true

构建partitioned_rels链表

(gdb) n
1406            if (IS_SIMPLE_REL(rel))
(gdb) 
1407                partitioned_rels = list_make1(rel->partitioned_child_rels);
(gdb) 
1433            Assert(list_length(partitioned_rels) >= 1);
(gdb) 
1441        foreach(l, live_childrels)
(gdb) p *partitioned_rels
$18 = {type = T_List, length = 1, head = 0x1fcff40, tail = 0x1fcff40}

开始遍历live_childrels,对于每一个非虚拟子关系,记录成本最低的访问路径.
如果子关系存在非参数化的总成本最低的访问路径,添加此路径到我们为父关系构建的非参数化的Append访问路径中.

(gdb) n
1443            RelOptInfo *childrel = lfirst(l);
(gdb) 
1445            Path       *cheapest_partial_path = NULL;
(gdb) 
1451            if (rel->rtekind == RTE_SUBQUERY && childrel->partitioned_child_rels != NIL)
(gdb) 
1463            if (childrel->pathlist != NIL &&
(gdb) 
1464                childrel->cheapest_total_path->param_info == NULL)
(gdb) 
1463            if (childrel->pathlist != NIL &&
(gdb) 
1465                accumulate_append_subpath(childrel->cheapest_total_path,

同样的思路,处理并行处理中的部分计划

(gdb) n
1471            if (childrel->partial_pathlist != NIL)
(gdb) 
1473                cheapest_partial_path = linitial(childrel->partial_pathlist);
(gdb) 
1474                accumulate_append_subpath(cheapest_partial_path,

同样的,处理并行append混合并行/非并行访问路径

(gdb) n
1486                Path       *nppath = NULL;
(gdb) 
1489                    get_cheapest_parallel_safe_total_inner(childrel->pathlist);
(gdb) 
1488                nppath =
(gdb) 
1491                if (cheapest_partial_path == NULL && nppath == NULL)
(gdb) 
1496                else if (nppath == NULL ||
(gdb) 
1498                          cheapest_partial_path->total_cost < nppath->total_cost))
(gdb) 
1497                         (cheapest_partial_path != NULL &&
(gdb) 
1501                    Assert(cheapest_partial_path != NULL);
(gdb) 
1502                    accumulate_append_subpath(cheapest_partial_path,

收集子关系所有可用的排序和参数化路径链表.

(gdb) 
1534            foreach(lcp, childrel->pathlist)
(gdb) 
(gdb) n
1536                Path       *childpath = (Path *) lfirst(lcp);
(gdb) 
1537                List       *childkeys = childpath->pathkeys;
(gdb) 
1538                Relids      childouter = PATH_REQ_OUTER(childpath);
(gdb) 
1541                if (childkeys != NIL)
(gdb) 
1567                if (childouter)
(gdb) 
1534            foreach(lcp, childrel->pathlist)

继续下一个子关系,完成处理

...
(gdb) 
1441        foreach(l, live_childrels)
(gdb) 
1598        if (subpaths_valid)

如存在子关系的非参数化访问路径,构建未排序/未参数化的Append访问路径.

(gdb) n
1599            add_path(rel, (Path *) create_append_path(root, rel, subpaths, NIL,
    (gdb) p *rel->pathlist
Cannot access memory at address 0x0
(gdb) n
1607        if (partial_subpaths_valid)
(gdb) p *rel->pathlist
$22 = {type = T_List, length = 1, head = 0x1fd0230, tail = 0x1fd0230}

尝试未排序/未参数化的部分Append访问路径.如可能,构建parallel-aware访问路径.

...
(gdb) 
1641            appendpath = create_append_path(root, rel, NIL, partial_subpaths,
(gdb) 
1650            partial_rows = appendpath->path.rows;
(gdb) 
1653            add_partial_path(rel, (Path *) appendpath);
(gdb)

使用混合的部分和非部分并行的append.

1662        if (pa_subpaths_valid && pa_nonpartial_subpaths != NIL)
(gdb)

基于收集的子路径键,构建非参数化的MergeAppend访问路径

1701        if (subpaths_valid)
(gdb) 
1702            generate_mergeappend_paths(root, rel, live_childrels,

完成调用

(gdb) 
1719        foreach(l, all_child_outers)
(gdb) 
1757    }
(gdb) 
set_append_rel_pathlist (root=0x1f1cdb8, rel=0x1fc1800, rti=1, rte=0x1efa3d0) at allpaths.c:1354
1354    }
(gdb) p *rel->pathlist
$23 = {type = T_List, length = 1, head = 0x1fd0230, tail = 0x1fd0230}
(gdb) 
(gdb) p *(Node *)rel->pathlist->head->data.ptr_value
$24 = {type = T_AppendPath}
(gdb) p *(AppendPath *)rel->pathlist->head->data.ptr_value
$25 = {path = {type = T_AppendPath, pathtype = T_Append, parent = 0x1fc1800, pathtarget = 0x1fc1a38, param_info = 0x0, 
    parallel_aware = false, parallel_safe = true, parallel_workers = 0, rows = 6, startup_cost = 0, 
    total_cost = 30.530000000000001, pathkeys = 0x0}, partitioned_rels = 0x1fd01f8, subpaths = 0x1fcffc8, 
  first_partial_path = 2}

结束调用

(gdb) n
set_rel_pathlist (root=0x1f1cdb8, rel=0x1fc1800, rti=1, rte=0x1efa3d0) at allpaths.c:495
495     if (rel->reloptkind == RELOPT_BASEREL &&
(gdb) 
496         bms_membership(root->all_baserels) != BMS_SINGLETON)
(gdb) 
495     if (rel->reloptkind == RELOPT_BASEREL &&
(gdb) 
504     if (set_rel_pathlist_hook)
(gdb) 
508     set_cheapest(rel);
(gdb) 
513 }
(gdb)

感谢各位的阅读!关于“PostgreSQL如何为append relation构建访问路径”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!

阅读原文内容投诉

免责声明:

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

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

软考中级精品资料免费领

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

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

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

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

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

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

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