diff --git a/src/gausskernel/optimizer/path/costsize.cpp b/src/gausskernel/optimizer/path/costsize.cpp index 22209c888..3638b8698 100644 --- a/src/gausskernel/optimizer/path/costsize.cpp +++ b/src/gausskernel/optimizer/path/costsize.cpp @@ -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