This commit is contained in:
yangke1125 2023-10-04 20:40:19 +08:00
parent 15fcbf46f3
commit ae60a2b832
1 changed files with 147 additions and 104 deletions

View File

@ -5400,51 +5400,63 @@ if (list_length(qual_list) >= 2) {
* if outerpath or innerpath is not stream, we should use global tuples for both.
* When parallel broadcast or local broadcast, the inner_tuples refer to tuples in a DN, so we divide dop.
*/
if (IsA(path->outerjoinpath, StreamPath) && (STREAM_BROADCAST == ((StreamPath*)path->outerjoinpath)->type)) {
outer_global_tuples = outer_tuples / dop;
} else if (IsA(path->innerjoinpath, StreamPath) &&
(((StreamPath*)path->innerjoinpath)->type == STREAM_BROADCAST)) {
inner_global_tuples = inner_tuples / dop;
} else if (IsA(path->outerjoinpath, StreamPath) && ((StreamPath*)path->outerjoinpath)->smpDesc &&
((StreamPath*)path->outerjoinpath)->smpDesc->distriType == LOCAL_BROADCAST) {
outer_global_tuples = outer_global_tuples / dop;
} else if (IsA(path->innerjoinpath, StreamPath) && ((StreamPath*)path->innerjoinpath)->smpDesc &&
((StreamPath*)path->innerjoinpath)->smpDesc->distriType == LOCAL_BROADCAST) {
inner_global_tuples = inner_global_tuples / dop;
}
tuples = selec * outer_global_tuples * inner_global_tuples;
/* estimate local relation sizes. */
tuples = get_local_rows(tuples,
path->path.multiple,
IsLocatorReplicated(path->path.locator_type),
ng_get_dest_num_data_nodes(&path->path)) /
dop;
} else
tuples = selec * outer_tuples * inner_tuples;
/* free space used by extended statistic */
if (es != NULL) {
qual_list = NIL;
list_free_ext(es->unmatched_clause_group);
delete es;
MemoryContextDelete(ExtendedStat);
}
ereport(DEBUG1,
(errmodule(MOD_OPT_JOIN),
errmsg("hashjointuples=%.0f, outer_tuples=%.0f, inner_tuples=%.0f, outer_global_tuples=%.0f, "
"inner_global_tuples=%.0f, selec=%.10f, multiple=%.0f,",
tuples,
outer_tuples,
inner_tuples,
outer_global_tuples,
inner_global_tuples,
selec,
path->path.multiple)));
return clamp_row_est(tuples);
// 检查外部和内部连接路径是否是流式路径并且连接类型是STREAM_BROADCAST
if (IsA(path->outerjoinpath, StreamPath) && (STREAM_BROADCAST == ((StreamPath*)path->outerjoinpath)->type)) {
// 如果是将外部连接的全局元组数除以并行度dop来估算本地元组数
outer_global_tuples = outer_tuples / dop;
} else if (IsA(path->innerjoinpath, StreamPath) &&
(((StreamPath*)path->innerjoinpath)->type == STREAM_BROADCAST)) {
// 如果内部连接是流式路径并且连接类型是STREAM_BROADCAST也将内部连接的全局元组数除以并行度
inner_global_tuples = inner_tuples / dop;
} else if (IsA(path->outerjoinpath, StreamPath) && ((StreamPath*)path->outerjoinpath)->smpDesc &&
((StreamPath*)path->outerjoinpath)->smpDesc->distriType == LOCAL_BROADCAST) {
// 如果外部连接是流式路径,并且具有本地广播分布,则将外部连接的全局元组数除以并行度
outer_global_tuples = outer_global_tuples / dop;
} else if (IsA(path->innerjoinpath, StreamPath) && ((StreamPath*)path->innerjoinpath)->smpDesc &&
((StreamPath*)path->innerjoinpath)->smpDesc->distriType == LOCAL_BROADCAST) {
// 如果内部连接是流式路径,并且具有本地广播分布,则将内部连接的全局元组数除以并行度
inner_global_tuples = inner_global_tuples / dop;
}
// 计算连接路径的元组数估算
tuples = selec * outer_global_tuples * inner_global_tuples;
// 如果连接路径需要本地元组数估算则调用get_local_rows来估算
if (IsLocatorReplicated(path->path.locator_type)) {
tuples = get_local_rows(tuples,
path->path.multiple,
IsLocatorReplicated(path->path.locator_type),
ng_get_dest_num_data_nodes(&path->path)) /
dop;
} else {
// 否则,使用全局元组数估算
tuples = selec * outer_tuples * inner_tuples;
}
// 如果存在扩展统计信息对象es则清理相关资源
if (es != NULL) {
qual_list = NIL;
list_free_ext(es->unmatched_clause_group);
delete es;
MemoryContextDelete(ExtendedStat);
}
// 打印调试信息
ereport(DEBUG1,
(errmodule(MOD_OPT_JOIN),
errmsg("hashjointuples=%.0f, outer_tuples=%.0f, inner_tuples=%.0f, outer_global_tuples=%.0f, "
"inner_global_tuples=%.0f, selec=%.10f, multiple=%.0f,",
tuples,
outer_tuples,
inner_tuples,
outer_global_tuples,
inner_global_tuples,
selec,
path->path.multiple)));
// 返回经过限制的元组数估算
return clamp_row_est(tuples);
}
/*
* set_baserel_size_estimates
* Set the size estimates for the given base relation.
@ -5463,16 +5475,22 @@ void set_baserel_size_estimates(PlannerInfo* root, RelOptInfo* rel)
double nrows;
/* Should only be applied to base relations */
AssertEreport(
rel->relid > 0, MOD_OPT, "The relid is invalid when set the size estimates for the given base relation.");
// 检查关系的 relid 是否有效
AssertEreport(
rel->relid > 0, MOD_OPT, "The relid is invalid when set the size estimates for the given base relation.");
nrows = rel->tuples * clauselist_selectivity(root, rel->baserestrictinfo, 0, JOIN_INNER, NULL);
// 通过对基本关系的元组数和限制条件进行选择度估算来估算行数
nrows = rel->tuples * clauselist_selectivity(root, rel->baserestrictinfo, 0, JOIN_INNER, NULL);
rel->rows = clamp_row_est(nrows);
// 使用 clamp_row_est 限制行数的估算值
rel->rows = clamp_row_est(nrows);
cost_qual_eval(&rel->baserestrictcost, rel->baserestrictinfo, root);
// 计算基本关系的限制条件代价
cost_qual_eval(&rel->baserestrictcost, rel->baserestrictinfo, root);
// 设置基本关系的宽度估算
set_rel_width(root, rel);
set_rel_width(root, rel);
}
/*
@ -5587,23 +5605,33 @@ void set_joinrel_size_estimates(PlannerInfo* root, RelOptInfo* rel, RelOptInfo*
*/
void set_joinpath_multiple_for_EC(PlannerInfo* root, Path* path, Path* outer_path, Path* inner_path)
{
if (path == NULL || outer_path == NULL || inner_path == NULL || root == NULL) {
return;
}
// 检查传入的路径和规划信息是否有效
if (path == NULL || outer_path == NULL || inner_path == NULL || root == NULL) {
return;
}
RangeTblEntry* rte = NULL;
RangeTblEntry* rte = NULL;
if (outer_path->pathtype == T_FunctionScan) {
rte = planner_rt_fetch(outer_path->parent->relid, root);
if (IS_EC_FUNC(rte)) {
path->multiple = outer_path->parent->multiple;
}
} else if (inner_path->pathtype == T_FunctionScan) {
rte = planner_rt_fetch(inner_path->parent->relid, root);
if (IS_EC_FUNC(rte)) {
path->multiple = inner_path->parent->multiple;
}
// 检查外部路径的类型是否为 FunctionScan
if (outer_path->pathtype == T_FunctionScan) {
// 获取外部路径关联的 RangeTblEntryRange Table Entry
rte = planner_rt_fetch(outer_path->parent->relid, root);
// 检查 RangeTblEntry 是否与 Equivalence Class 相关
if (IS_EC_FUNC(rte)) {
// 如果是与 EC 相关的函数扫描,则将路径的 multiple 设置为外部路径的 multiple
path->multiple = outer_path->parent->multiple;
}
}
// 如果外部路径不是 FunctionScan再检查内部路径
else if (inner_path->pathtype == T_FunctionScan) {
// 获取内部路径关联的 RangeTblEntry
rte = planner_rt_fetch(inner_path->parent->relid, root);
// 检查 RangeTblEntry 是否与 Equivalence Class 相关
if (IS_EC_FUNC(rte)) {
// 如果是与 EC 相关的函数扫描,则将路径的 multiple 设置为内部路径的 multiple
path->multiple = inner_path->parent->multiple;
}
}
return;
}
@ -5710,44 +5738,50 @@ static double calc_joinrel_size_estimate(PlannerInfo* root, double outer_rows, d
* For JOIN_SEMI and JOIN_ANTI, the selectivity is defined as the fraction
* of LHS rows that have matches, and we apply that straightforwardly.
*/
switch (jointype) {
case JOIN_INNER:
nrows = outer_rows * inner_rows * jselec;
break;
case JOIN_LEFT:
nrows = outer_rows * inner_rows * jselec;
if (nrows < outer_rows)
nrows = outer_rows;
nrows *= pselec;
break;
case JOIN_FULL:
nrows = outer_rows * inner_rows * jselec;
if (nrows < outer_rows)
nrows = outer_rows;
if (nrows < inner_rows)
nrows = inner_rows;
nrows *= pselec;
break;
case JOIN_SEMI:
nrows = outer_rows * jselec;
/* pselec not used */
break;
case JOIN_ANTI:
case JOIN_LEFT_ANTI_FULL:
nrows = outer_rows * (1.0 - jselec);
nrows *= pselec;
break;
default: {
/* other values not expected here */
ereport(ERROR,
(errmodule(MOD_OPT),
errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE),
errmsg("unrecognized join type when calculate joinrel size estimate: %d", (int)jointype)));
nrows = 0; /* keep compiler quiet */
} break;
}
switch (jointype) {
case JOIN_INNER:
// 内连接INNER JOIN的行数估算
nrows = outer_rows * inner_rows * jselec;
break;
case JOIN_LEFT:
// 左连接LEFT JOIN的行数估算
nrows = outer_rows * inner_rows * jselec;
if (nrows < outer_rows)
nrows = outer_rows;
nrows *= pselec;
break;
case JOIN_FULL:
// 全外连接FULL OUTER JOIN的行数估算
nrows = outer_rows * inner_rows * jselec;
if (nrows < outer_rows)
nrows = outer_rows;
if (nrows < inner_rows)
nrows = inner_rows;
nrows *= pselec;
break;
case JOIN_SEMI:
// 半连接SEMI JOIN的行数估算
nrows = outer_rows * jselec;
break;
case JOIN_ANTI:
case JOIN_LEFT_ANTI_FULL:
// 反连接ANTI JOIN、左反连接LEFT ANTI JOIN和左全外连接LEFT FULL ANTI JOIN的行数估算
nrows = outer_rows * (1.0 - jselec);
nrows *= pselec;
break;
default: {
// 处理未识别的连接类型
ereport(ERROR,
(errmodule(MOD_OPT),
errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE),
errmsg("unrecognized join type when calculate joinrel size estimate: %d", (int)jointype)));
nrows = 0; // 如果连接类型未知则将行数估算为0
} break;
}
return clamp_row_est(nrows);
// 使用 clamp_row_est 函数确保行数估算不小于0
return clamp_row_est(nrows);
}
/*
@ -5762,29 +5796,38 @@ static double calc_joinrel_size_estimate(PlannerInfo* root, double outer_rows, d
*/
void set_subquery_size_estimates(PlannerInfo* root, RelOptInfo* rel)
{
PlannerInfo* subroot = rel->subroot;
RangeTblEntry PG_USED_FOR_ASSERTS_ONLY* rte = NULL;
PlannerInfo* subroot = rel->subroot; // 子查询的规划信息
RangeTblEntry PG_USED_FOR_ASSERTS_ONLY* rte = NULL; // 范围表RangeTblEntry
ListCell* lc = NULL;
/* Should only be applied to base relations that are subqueries */
// 断言:确保关系的 relid 大于0表示这是一个有效的关系
AssertEreport(rel->relid > 0,
MOD_OPT,
"The relid is invalid when set the size estimates for a base relation that is a subquery.");
// 获取与关系相关的范围表项RangeTblEntry
rte = planner_rt_fetch(rel->relid, root);
// 断言:只有在 FROM 子句中的子查询才支持这种操作
AssertEreport(rte->rtekind == RTE_SUBQUERY,
MOD_OPT,
"Only subquery in FROM clause can be supported"
"when set the size estimates for a base relation that is a subquery.");
/* Copy raw number of output rows from subplan */
// 如果子查询具有执行节点信息,确定定位器类型
if (rel->subplan->exec_nodes != NULL)
rel->locator_type = rel->subplan->exec_nodes->baselocatortype;
// 根据定位器类型来设置关系的行数估算值
if (rel->locator_type != LOCATOR_TYPE_REPLICATED)
rel->tuples = rel->subplan->plan_rows;
else
rel->tuples = PLAN_LOCAL_ROWS(rel->subplan);
// 设置关系的本地大小信息
set_local_rel_size(root, rel);
/*
* Compute per-output-column width estimates by examining the subquery's
* targetlist. For any output that is a plain Var, get the width estimate