Enter
This commit is contained in:
parent
15fcbf46f3
commit
ae60a2b832
|
|
@ -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) {
|
||||
// 获取外部路径关联的 RangeTblEntry(Range 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
|
||||
|
|
|
|||
Loading…
Reference in New Issue