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