返回顶部
首页 > 资讯 > 数据库 >PostgreSQL如何为append relation构建访问路径
  • 120
分享到

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

2024-04-02 19:04:59 120人浏览 八月长安
摘要

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

这篇文章给大家分享的是有关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构建访问路径”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!

您可能感兴趣的文档:

--结束END--

本文标题: PostgreSQL如何为append relation构建访问路径

本文链接: https://lsjlt.com/news/64731.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • PostgreSQL如何为append relation构建访问路径
    这篇文章给大家分享的是有关PostgreSQL如何为append relation构建访问路径的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一、数据结构AppendRelInfo...
    99+
    2024-04-02
  • PostgreSQL中哪个函数为连接新生成的joinrel构造访问路径
    本篇内容主要讲解“PostgreSQL中哪个函数为连接新生成的joinrel构造访问路径”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“PostgreSQL中哪个...
    99+
    2024-04-02
  • tomcat如何查看项目访问路径
    要查看Tomcat项目的访问路径,可以按照以下步骤操作: 打开Tomcat服务器的安装目录,找到`conf`文件夹。 在`conf...
    99+
    2023-10-27
    tomcat
  • thinkphp加路径访问不到如何解决
    本篇内容主要讲解“thinkphp加路径访问不到如何解决”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“thinkphp加路径访问不到如何解决”吧!一、问题原因当我们在页面中加入路径时,例如:&l...
    99+
    2023-07-05
  • win7无法访问指定路径如何解决
    如果您的Windows 7无法访问指定路径,可以尝试以下解决方法:1. 检查路径是否正确:确保您输入的路径是正确的,并且没有任何拼写...
    99+
    2023-09-01
    win7
  • Windows下如何使用PHP访问文件路径?
    当我们在Windows下使用PHP时,经常需要访问文件路径,这是一个非常常见的需求。在本文中,我们将介绍如何使用PHP访问文件路径。 首先,我们需要知道Windows下文件路径的格式。Windows下的文件路径格式是以盘符开头,例如C:Wi...
    99+
    2023-07-01
    path windows shell
  • vue中要如何根据路径来访问文件
    本文小编为大家详细介绍“vue中要如何根据路径来访问文件”,内容详细,步骤清晰,细节处理妥当,希望这篇“vue中要如何根据路径来访问文件”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。一般情况下,Vue.js 的文...
    99+
    2023-07-05
  • win7无法访问指定设备路径如何解决
    要解决Windows 7无法访问指定设备路径的问题,可以尝试以下方法:1. 检查设备连接:确保设备已正确连接到计算机,并且设备驱动程...
    99+
    2023-09-09
    win7
  • ASP IDE路径并发:如何应对大规模访问?
    在ASP IDE中,路径并发是指多个用户同时访问同一个路径的情况。当出现大规模的并发访问时,服务器可能会出现响应慢、卡顿、甚至崩溃的情况。为了避免这种情况的发生,我们需要采取一些措施来应对大规模的路径并发。 一、使用缓存 缓存可以提高应用...
    99+
    2023-10-11
    ide path 并发
  • 在java构建路径找不到超类如何解决
    在 Java 中,如果找不到超类(即父类),可以尝试以下几种解决方法:1. 检查是否正确导入了所需的类。确保父类的包路径是正确的,并...
    99+
    2023-10-07
    java
  • Angular项目路径如何添加指定的访问前缀
    这篇文章主要介绍了Angular项目路径如何添加指定的访问前缀的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Angular项目路径如何添加指定的访问前缀文章都会有所收获,下面我们一起来看看吧。开发多个项目的时候...
    99+
    2023-07-05
  • 如何构建云服务器内网访问
    确保用户已经获取了内网IP地址。 为内网用户分配一个公网IP地址。可以使用P2P协议来共享内网资源,从而实现内网访问。 为内网用户分配一个内网SSID名称,该名称可以是内网主机的名称或者应用程序的名称。 为内网主机提供访问控制列表(ACL...
    99+
    2023-10-27
    内网 服务器
  • 如何使用二维码增强ASP路径的可访问性?
    如何使用二维码增强ASP路径的可访问性? 随着互联网的发展,越来越多的网站采用ASP(Active Server Pages)来开发动态网页。而在ASP网站中,路径的可访问性是非常重要的。如果ASP路径无法被访问,那么网站就无法正常运行。 ...
    99+
    2023-10-06
    path 二维码 http
  • Angular项目中如何给路径添加指定访问前缀
    这篇“Angular项目中如何给路径添加指定访问前缀”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Angular项目中如何给...
    99+
    2023-07-05
  • 如何用Redis构建访问频率控制模块
    这篇文章主要讲解了“如何用Redis构建访问频率控制模块”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何用Redis构建访问频率控制模块”吧!  原理概述...
    99+
    2024-04-02
  • 如何解决Vue背景图打包之后访问路径错误的问题
    这篇文章主要介绍如何解决Vue背景图打包之后访问路径错误的问题,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!案例环境通过vue-cli脚手架创建的vue项目在项目打包的时候遇到了背景...
    99+
    2024-04-02
  • windows无法访问指定设备路径或文件夹如何解决
    今天小编给大家分享一下windows无法访问指定设备路径或文件夹如何解决的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。win...
    99+
    2023-07-02
  • NumPy路径问题:如何在PHP中处理复杂的数据结构?
    NumPy是一个广泛使用的Python科学计算库,它提供了高效的数组操作和数学函数,使得Python成为数据科学和机器学习领域中的重要语言之一。但是,当在PHP中处理NumPy数据结构时,我们可能会遇到一些路径问题。在本文中,我们将探讨如何...
    99+
    2023-09-11
    numpy path numy
  • nodejs构建本地web测试服务器 如何解决访问静态资源问题
    直接打开html文件,是以file:///方式打开的,这种方式很多时候会遇到跨域的问题,因此我们一般会搭建一个简易的本地服务器,来运行测试页面。 一、构建静态服务器 1、使用express模块 建立个js文...
    99+
    2022-06-04
    如何解决 静态 服务器
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作