forked from huawei/openGauss-server
Enter
This commit is contained in:
parent
3d69ac3ea8
commit
dc653b252b
|
|
@ -5775,7 +5775,7 @@ static double calc_joinrel_size_estimate(PlannerInfo* root, double outer_rows, d
|
|||
(errmodule(MOD_OPT),
|
||||
errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE),
|
||||
errmsg("unrecognized join type when calculate joinrel size estimate: %d", (int)jointype)));
|
||||
nrows = 0; // 如果连接类型未知,则将行数估算为0
|
||||
nrows = 0; // <EFBFBD><EFBFBD><EFBFBD>果连接类型未知,则将行数估算为0
|
||||
} break;
|
||||
}
|
||||
|
||||
|
|
@ -6045,31 +6045,41 @@ inline void set_rel_encode_info_if_vectorized(PlannerInfo *root, RelOptInfo *rel
|
|||
* The per-attribute width estimates are cached for possible re-use while
|
||||
* building join relations.
|
||||
*/
|
||||
// 设置关系的宽度估计
|
||||
void set_rel_width(PlannerInfo* root, RelOptInfo* rel)
|
||||
{
|
||||
// 获取关系的OID
|
||||
Oid reloid = planner_rt_fetch(rel->relid, root)->relid;
|
||||
// 初始化元组宽度为0
|
||||
int32 tuple_width = 0;
|
||||
// 初始化是否有整行变量的标志为false
|
||||
bool have_wholerow_var = false;
|
||||
// 遍历关系的目标列表
|
||||
ListCell* lc = NULL;
|
||||
|
||||
foreach (lc, rel->reltargetlist) {
|
||||
Node* node = (Node*)lfirst(lc);
|
||||
|
||||
// 检查节点是否是一个变量
|
||||
if (IsA(node, Var)) {
|
||||
Var* var = (Var*)node;
|
||||
int ndx;
|
||||
int32 item_width;
|
||||
|
||||
// 断言:变量的varno必须与关系的relid匹配
|
||||
AssertEreport(var->varno == rel->relid,
|
||||
MOD_OPT,
|
||||
"The varno does not match to relid when setting the estimated output width of a base relation.");
|
||||
// 断言:变量的varattno必须大于等于关系的最小属性
|
||||
AssertEreport(var->varattno >= rel->min_attr,
|
||||
MOD_OPT,
|
||||
"The varattno is less than min_attr when setting the estimated output width of a base relation.");
|
||||
// 断言:变量的varattno必须小于等于关系的最大属性
|
||||
AssertEreport(var->varattno <= rel->max_attr,
|
||||
MOD_OPT,
|
||||
"The varattno is larger than max_attr when setting the estimated output width of a base relation.");
|
||||
|
||||
// 计算属性在关系中的索引
|
||||
ndx = var->varattno - rel->min_attr;
|
||||
|
||||
/*
|
||||
|
|
@ -6092,31 +6102,42 @@ void set_rel_width(PlannerInfo* root, RelOptInfo* rel)
|
|||
}
|
||||
|
||||
/* Try to get column width from statistics */
|
||||
if (reloid != InvalidOid && var->varattno > 0) {
|
||||
Oid targetid = reloid;
|
||||
bool ispartition = false;
|
||||
RangeTblEntry* rte = planner_rt_fetch(rel->relid, root);
|
||||
// 检查关系的OID是否有效,以及变量的varattno是否大于0
|
||||
if (reloid != InvalidOid && var->varattno > 0) {
|
||||
Oid targetid = reloid;
|
||||
bool ispartition = false;
|
||||
RangeTblEntry* rte = planner_rt_fetch(rel->relid, root);
|
||||
|
||||
if (rte->isContainPartition) {
|
||||
AssertEreport(OidIsValid(rte->partitionOid),
|
||||
MOD_OPT,
|
||||
"The partitionOid is invalid when setting the estimated output width of a base relation.");
|
||||
targetid = rte->partitionOid;
|
||||
ispartition = true;
|
||||
}
|
||||
// 如果关系包含分区,则使用分区OID作为目标ID
|
||||
if (rte->isContainPartition) {
|
||||
// 断言:分区OID必须有效
|
||||
AssertEreport(OidIsValid(rte->partitionOid),
|
||||
MOD_OPT,
|
||||
"The partitionOid is invalid when setting the estimated output width of a base relation.");
|
||||
targetid = rte->partitionOid;
|
||||
ispartition = true;
|
||||
}
|
||||
|
||||
if (rte->isContainSubPartition) {
|
||||
Assert(OidIsValid(rte->partitionOid));
|
||||
targetid = rte->subpartitionOid;
|
||||
ispartition = true;
|
||||
}
|
||||
// 如果关系包含子分区,则使用子分区OID作为目标ID
|
||||
if (rte->isContainSubPartition) {
|
||||
// 断言:分区OID必须有效
|
||||
Assert(OidIsValid(rte->partitionOid));
|
||||
targetid = rte->subpartitionOid;
|
||||
ispartition = true;
|
||||
}
|
||||
|
||||
// 获取属性的平均宽度
|
||||
item_width = get_attavgwidth(targetid, var->varattno, ispartition);
|
||||
// 如果属性宽度大于0
|
||||
if (item_width > 0) {
|
||||
// 将属性宽度存储在关系的attr_widths数组中
|
||||
rel->attr_widths[ndx] = item_width;
|
||||
// 增加元组宽度
|
||||
tuple_width += item_width;
|
||||
// 设置关系的编码信息(如果是矢量化计划)
|
||||
set_rel_encode_info_if_vectorized(root, rel, var->vartype, item_width);
|
||||
continue;
|
||||
|
||||
item_width = get_attavgwidth(targetid, var->varattno, ispartition);
|
||||
if (item_width > 0) {
|
||||
rel->attr_widths[ndx] = item_width;
|
||||
tuple_width += item_width;
|
||||
set_rel_encode_info_if_vectorized(root, rel, var->vartype, item_width);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -6132,7 +6153,7 @@ void set_rel_width(PlannerInfo* root, RelOptInfo* rel)
|
|||
rel->attr_widths[ndx] = item_width;
|
||||
tuple_width += item_width;
|
||||
set_rel_encode_info_if_vectorized(root, rel, var->vartype, item_width);
|
||||
} else if (IsA(node, PlaceHolderVar)) {
|
||||
} else if (IsA(node, PlaceHolderVar)) {// 如果变量不是Var类型,则进入这个分支
|
||||
PlaceHolderVar* phv = (PlaceHolderVar*)node;
|
||||
PlaceHolderInfo* phinfo = find_placeholder_info(root, phv, false);
|
||||
|
||||
|
|
@ -6146,13 +6167,17 @@ void set_rel_width(PlannerInfo* root, RelOptInfo* rel)
|
|||
*/
|
||||
int32 item_width;
|
||||
|
||||
item_width = get_typavgwidth(exprType(node), exprTypmod(node));
|
||||
AssertEreport(item_width > 0,
|
||||
MOD_OPT,
|
||||
"The estimated average width of values of the type is not larger than 0"
|
||||
"when setting the estimated output width of a base relation.");
|
||||
// 获取节点的类型和类型修饰符,然后计算平均宽度
|
||||
item_width = get_typavgwidth(exprType(node), exprTypmod(node));
|
||||
// 断言:宽度必须大于0
|
||||
AssertEreport(item_width > 0,
|
||||
MOD_OPT,
|
||||
"The estimated average width of values of the type is not larger than 0"
|
||||
"when setting the estimated output width of a base relation.");
|
||||
|
||||
tuple_width += item_width;
|
||||
// 增加元组宽度
|
||||
tuple_width += item_width;
|
||||
// 设置关系的编码信息(如果是矢量化计划)
|
||||
set_rel_encode_info_if_vectorized(root, rel, exprType(node), item_width);
|
||||
}
|
||||
}
|
||||
|
|
@ -6161,7 +6186,8 @@ void set_rel_width(PlannerInfo* root, RelOptInfo* rel)
|
|||
* If we have a whole-row reference, estimate its width as the sum of
|
||||
* per-column widths plus sizeof(HeapTupleHeaderData).
|
||||
*/
|
||||
if (have_wholerow_var) {
|
||||
if (have_wholerow_var) {
|
||||
// 如果有整行变量,计算整行的宽度
|
||||
int32 wholerow_width = sizeof(HeapTupleHeaderData);
|
||||
|
||||
if (reloid != InvalidOid) {
|
||||
|
|
@ -6180,18 +6206,31 @@ void set_rel_width(PlannerInfo* root, RelOptInfo* rel)
|
|||
partid = rte->subpartitionOid;
|
||||
}
|
||||
|
||||
/* Real relation, so estimate true tuple width */
|
||||
// 获取关系数据的宽度,包括主表和分区
|
||||
wholerow_width += get_relation_data_width(reloid, partid, rel->attr_widths - rel->min_attr);
|
||||
} else {
|
||||
/* Do what we can with info for a phony rel */
|
||||
// 获取关系的宽度,包括所有属性
|
||||
AttrNumber i;
|
||||
|
||||
for (i = 1; i <= rel->max_attr; i++)
|
||||
wholerow_width += rel->attr_widths[i - rel->min_attr];
|
||||
}
|
||||
|
||||
// 将整行的宽度设置到关系的属性宽度数组中
|
||||
rel->attr_widths[0 - rel->min_attr] = wholerow_width;
|
||||
|
||||
// 增加元组宽度
|
||||
tuple_width += wholerow_width;
|
||||
}
|
||||
|
||||
// 断言:元组宽度必须大于或等于0
|
||||
AssertEreport(tuple_width >= 0,
|
||||
MOD_OPT,
|
||||
"The estimated width of tuple is less than 0"
|
||||
"when setting the estimated output width of a base relation.");
|
||||
// 将元组宽度设置到关系的宽度属性中
|
||||
rel->width = tuple_width;
|
||||
|
||||
|
||||
/*
|
||||
* Include the whole-row Var as part of the output tuple. Yes, that
|
||||
* really is what happens at runtime.
|
||||
|
|
@ -6225,32 +6264,35 @@ void set_rel_width(PlannerInfo* root, RelOptInfo* rel)
|
|||
*/
|
||||
double relation_byte_size(double tuples, int width, bool vectorized, bool aligned, bool issort, bool indexsort)
|
||||
{
|
||||
// 断言:宽度必须大于或等于0
|
||||
Assert(width >= 0);
|
||||
|
||||
// 计算头部大小,根据是否排序和是否索引排序来选择不同的头部类型
|
||||
size_t header_size = (issort && indexsort) ? sizeof(IndexTupleData) : sizeof(HeapTupleHeaderData);
|
||||
|
||||
if (aligned) {
|
||||
if (vectorized)
|
||||
// 返回关系的字节大小,考虑了对齐
|
||||
return tuples * (TUPLE_OVERHEAD(true) + width);
|
||||
else
|
||||
// 返回关系的字节大小,考虑了对齐和分配块大小
|
||||
return tuples *
|
||||
(TUPLE_OVERHEAD(issort) + alloc_trunk_size(MAXALIGN((uintptr_t)width) + MAXALIGN(header_size)));
|
||||
} else {
|
||||
// 返回关系的字节大小,不考虑对齐
|
||||
return tuples * (MAXALIGN((uintptr_t)width) + MAXALIGN(header_size));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* page_size
|
||||
* Returns an estimate of the number of pages covered by a given
|
||||
* number of tuples of a given width (size in bytes).
|
||||
*/
|
||||
double page_size(double tuples, int width)
|
||||
{
|
||||
// 计算关系所占用的页数
|
||||
return ceil(relation_byte_size(tuples, width, false) / BLCKSZ);
|
||||
}
|
||||
|
||||
/* it used to compute page_size in createplan.cpp */
|
||||
double cost_page_size(double tuples, int width)
|
||||
{
|
||||
// 计算成本中的页数
|
||||
return page_size(tuples, width);
|
||||
}
|
||||
|
||||
|
|
@ -6261,8 +6303,11 @@ double cost_page_size(double tuples, int width)
|
|||
*/
|
||||
void restore_hashjoin_cost(Path* path)
|
||||
{
|
||||
// 如果启用了哈希连接成本修改并且路径是哈希路径
|
||||
if (u_sess->attr.attr_sql.enable_change_hjcost && IsA(path, HashPath)) {
|
||||
// 获取内部路径
|
||||
Path* innerpath = ((HashPath*)path)->jpath.innerjoinpath;
|
||||
// 恢复哈希连接的启动成本
|
||||
path->startup_cost += innerpath->total_cost - innerpath->startup_cost;
|
||||
}
|
||||
}
|
||||
|
|
@ -6385,34 +6430,42 @@ void hybrid_samplescangetsamplesize(PlannerInfo* root, RelOptInfo* baserel, List
|
|||
ListCell* lc = NULL;
|
||||
uint16 i = 0;
|
||||
|
||||
// 断言:样本参数数量必须等于2
|
||||
AssertEreport(SAMPLEARGSNUM == list_length(paramexprs),
|
||||
MOD_OPT,
|
||||
"The number of sample percentage info does not equal 2"
|
||||
"when setting the estimated output width of a base relation.");
|
||||
|
||||
foreach (lc, paramexprs) {
|
||||
Node* paramnode = (Node*)lfirst(lc);
|
||||
Node* pctnode = estimate_expression_value(root, paramnode);
|
||||
float4 samplefract = 0.0;
|
||||
|
||||
// 检查是否成功估算了百分比值
|
||||
if (likely(pctnode)) {
|
||||
samplefract = get_samplefract(pctnode);
|
||||
} else {
|
||||
// 如果估算失败,报告错误
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNEXPECTED_NULL_VALUE),
|
||||
errmsg("Fail to estimate expression value.")));
|
||||
}
|
||||
|
||||
if (i == SYSTEM_SAMPLE) {
|
||||
/* We'll visit a sample of the pages ... */
|
||||
/* 我们将访问页面的一部分... */
|
||||
// 更新关系的页面数,以考虑样本抽取
|
||||
baserel->pages = clamp_row_est(baserel->pages * samplefract);
|
||||
}
|
||||
|
||||
/* ... and hopefully get a representative number of tuples from them */
|
||||
/* ... 并希望从中获得代表性的元组数量 */
|
||||
// 更新关系的元组数,以考虑样本抽取
|
||||
baserel->tuples = clamp_row_est(baserel->tuples * samplefract);
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* copy_mem_info
|
||||
* copy OpMemInfo structure from source to dest
|
||||
|
|
@ -6471,22 +6524,26 @@ bool has_complicate_hashkey(List* hashclauses, Relids inner_relids)
|
|||
{
|
||||
ListCell* lc = NULL;
|
||||
|
||||
// 遍历哈希关联条件列表
|
||||
foreach (lc, hashclauses) {
|
||||
RestrictInfo* restrictinfo = (RestrictInfo*)lfirst(lc);
|
||||
Node* innerkey = NULL;
|
||||
|
||||
// 断言:条件节点必须是 RestrictInfo 类型
|
||||
AssertEreport(IsA(restrictinfo, RestrictInfo),
|
||||
MOD_OPT,
|
||||
"The nodeTag of restrictinfo is not T_RestrictInfo"
|
||||
"when setting the estimated output width of a base relation.");
|
||||
|
||||
/*
|
||||
* First we have to figure out which side of the hashjoin clause
|
||||
* is the inner side.
|
||||
* 首先,我们需要确定哈希连接条件的哪一侧是内部侧。
|
||||
* 如果 restrictinfo 的右侧关系 ID 是 inner_relids 的子集,
|
||||
* 那么 innerkey 就是 restrictinfo 条件的右操作数,否则就是左操作数。
|
||||
*/
|
||||
if (bms_is_subset(restrictinfo->right_relids, inner_relids)) {
|
||||
innerkey = get_rightop(restrictinfo->clause);
|
||||
} else {
|
||||
// 断言:左侧关系 ID 必须是 inner_relids 的子集
|
||||
AssertEreport(bms_is_subset(restrictinfo->left_relids, inner_relids),
|
||||
MOD_OPT,
|
||||
"The left relids is not subset of the relids of inner side"
|
||||
|
|
@ -6494,7 +6551,7 @@ bool has_complicate_hashkey(List* hashclauses, Relids inner_relids)
|
|||
innerkey = get_leftop(restrictinfo->clause);
|
||||
}
|
||||
|
||||
/* Judge if the inner key is simple var */
|
||||
/* 判断内部键是否为简单变量 */
|
||||
if (innerkey != NULL && !IsA(innerkey, Var) &&
|
||||
!(IsA(innerkey, RelabelType) && IsA(((RelabelType*)innerkey)->arg, Var)))
|
||||
return true;
|
||||
|
|
@ -6503,6 +6560,7 @@ bool has_complicate_hashkey(List* hashclauses, Relids inner_relids)
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* calc_distributekey_width
|
||||
* Optimizer will add distribute key in the targetlist if not found in plan
|
||||
|
|
@ -6518,30 +6576,31 @@ bool has_complicate_hashkey(List* hashclauses, Relids inner_relids)
|
|||
*/
|
||||
static int calc_distributekey_width(Path* path, int* width, bool vectorized, bool aligned)
|
||||
{
|
||||
int num = 0;
|
||||
int num = 0; // 初始化计数器为0
|
||||
ListCell* lc = NULL;
|
||||
|
||||
/* Only do this for redistribute stream, since only redistribute has distribute keys */
|
||||
/* 只对分发流执行此操作,因为只有分发流有分发键 */
|
||||
if (IsA(path, StreamPath) && ((StreamPath*)path)->type == STREAM_REDISTRIBUTE) {
|
||||
foreach (lc, path->distribute_keys) {
|
||||
foreach (lc, path->distribute_keys) { // 遍历分发键列表
|
||||
Node* node = (Node*)lfirst(lc);
|
||||
if (!list_member(path->parent->reltargetlist, node)) {
|
||||
num++;
|
||||
int32 item_width = get_typavgwidth(exprType(node), exprTypmod(node));
|
||||
if (!list_member(path->parent->reltargetlist, node)) { // 检查节点是否不在目标列表中
|
||||
num++; // 增加计数器
|
||||
int32 item_width = get_typavgwidth(exprType(node), exprTypmod(node)); // 获取类型的平均宽度
|
||||
AssertEreport(item_width > 0,
|
||||
MOD_OPT,
|
||||
"The item width is not larger than 0 when setting the estimated output width of a base relation.");
|
||||
if (vectorized)
|
||||
*width += columnar_get_col_width(exprType(node), item_width, aligned);
|
||||
*width += columnar_get_col_width(exprType(node), item_width, aligned); // 计算列宽度
|
||||
else
|
||||
*width += item_width;
|
||||
*width += item_width; // 直接累加宽度
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return num;
|
||||
return num; // 返回计数器的值
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get_path_actual_total_width
|
||||
* In PG optimizer, only width of row engine is estimated, and it has
|
||||
|
|
@ -6561,33 +6620,35 @@ static int calc_distributekey_width(Path* path, int* width, bool vectorized, boo
|
|||
*/
|
||||
int get_path_actual_total_width(Path* path, bool vectorized, OpType type, int newcol)
|
||||
{
|
||||
int num_new_col = 0;
|
||||
int width = 0;
|
||||
bool aligned = (type >= OP_SORT);
|
||||
int num_new_col = 0; // 用于记录新列的数量
|
||||
int width = 0; // 用于记录宽度
|
||||
bool aligned = (type >= OP_SORT); // 根据操作类型是否需要对齐
|
||||
|
||||
if (path->parent == NULL) {
|
||||
return COL_TUPLE_WIDTH;
|
||||
return COL_TUPLE_WIDTH; // 如果路径的父节点为空,则返回默认列元组宽度
|
||||
}
|
||||
|
||||
/* For redistribute, we will add unmatched distribute key into targetlist, so count this */
|
||||
// 计算分发键的宽度,并将结果累加到 width 中
|
||||
num_new_col = calc_distributekey_width(path, &width, vectorized, aligned);
|
||||
|
||||
if (vectorized) {
|
||||
switch (type) {
|
||||
case OP_HASHJOIN:
|
||||
// 计算哈希连接操作的宽度
|
||||
width += path->parent->encodedwidth +
|
||||
SIZE_COL_VALUE * (list_length(path->parent->reltargetlist) + num_new_col + newcol);
|
||||
break;
|
||||
case OP_HASHAGG:
|
||||
// 计算哈希聚合操作的宽度
|
||||
width += path->parent->encodedwidth + TUPLE_OVERHEAD(true) + sizeof(void*) * 2 +
|
||||
SIZE_COL_VALUE * (list_length(path->parent->reltargetlist) + num_new_col + newcol);
|
||||
break;
|
||||
case OP_SORT:
|
||||
if (width != 0 || path->parent->encodednum != 0)
|
||||
newcol += 1;
|
||||
newcol += 1; // 如果排序操作,且宽度不为0或者已编码的列数不为0,增加新列
|
||||
/* No need break here. */
|
||||
case OP_MATERIAL:
|
||||
/* don't know encoded width of each column, just average them for a rough estimation */
|
||||
/* 不知道每列的编码宽度,只是对它们进行粗略估算的平均值 */
|
||||
if (path->parent->encodednum > 0)
|
||||
width += path->parent->encodednum *
|
||||
alloc_trunk_size(path->parent->encodedwidth / path->parent->encodednum);
|
||||
|
|
@ -6597,48 +6658,54 @@ int get_path_actual_total_width(Path* path, bool vectorized, OpType type, int ne
|
|||
break;
|
||||
}
|
||||
} else {
|
||||
width += path->parent->width;
|
||||
width += path->parent->width; // 非矢量化操作,直接使用父节点的宽度
|
||||
}
|
||||
|
||||
return width;
|
||||
return width; // 返回计算得到的总宽度
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get_subqueryscan_stream_cost
|
||||
* get stream_cost of a subquery
|
||||
*/
|
||||
static Cost get_subqueryscan_stream_cost(Plan* subplan)
|
||||
{
|
||||
Cost stream_cost = 0;
|
||||
Cost stream_cost = 0; // 初始化流成本为0
|
||||
|
||||
if (subplan == NULL)
|
||||
return stream_cost;
|
||||
return stream_cost; // 如果子计划为空,直接返回0
|
||||
|
||||
switch (nodeTag(subplan)) {
|
||||
case T_HashJoin:
|
||||
case T_VecHashJoin:
|
||||
// 对于哈希连接计划节点,递归调用左子树的流成本
|
||||
stream_cost = get_subqueryscan_stream_cost(subplan->lefttree);
|
||||
break;
|
||||
|
||||
case T_NestLoop:
|
||||
case T_VecNestLoop:
|
||||
// 对于嵌套循环计划节点,递归调用右子树的流成本
|
||||
stream_cost = get_subqueryscan_stream_cost(subplan->righttree);
|
||||
break;
|
||||
|
||||
case T_MergeJoin:
|
||||
case T_VecMergeJoin:
|
||||
// 对于归并连接计划节点,递归调用右子树的流成本
|
||||
stream_cost = get_subqueryscan_stream_cost(subplan->righttree);
|
||||
break;
|
||||
|
||||
case T_Stream:
|
||||
case T_VecStream:
|
||||
// 对于流计划节点,流成本等于启动成本
|
||||
stream_cost = subplan->startup_cost;
|
||||
break;
|
||||
|
||||
default:
|
||||
// 对于其他计划节点类型,递归调用左子树的流成本
|
||||
stream_cost = get_subqueryscan_stream_cost(subplan->lefttree);
|
||||
break;
|
||||
}
|
||||
|
||||
return stream_cost;
|
||||
return stream_cost; // 返回计算得到的流成本
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue