get_matching_partitions函數(shù)怎么用,小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,希?..."/>
您好,登錄后才能下訂單哦!
這篇文章將為大家詳細(xì)講解有關(guān)PostgreSQL中prune_append_rel_partitions->get_matching_partitions函數(shù)怎么用,小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。
PartitionScheme
分區(qū)方案,根據(jù)設(shè)計(jì),分區(qū)方案只包含分區(qū)方法的一般屬性(列表與范圍、分區(qū)列的數(shù)量和每個(gè)分區(qū)列的類型信息),而不包含特定的分區(qū)邊界信息。
/* * If multiple relations are partitioned the same way, all such partitions * will have a pointer to the same PartitionScheme. A list of PartitionScheme * objects is attached to the PlannerInfo. By design, the partition scheme * incorporates only the general properties of the partition method (LIST vs. * RANGE, number of partitioning columns and the type information for each) * and not the specific bounds. * 如果多個(gè)關(guān)系以相同的方式分區(qū),那么所有這些分區(qū)都將具有指向相同PartitionScheme的指針。 * PartitionScheme對(duì)象的鏈表附加到PlannerInfo中。 * 根據(jù)設(shè)計(jì),分區(qū)方案只包含分區(qū)方法的一般屬性(列表與范圍、分區(qū)列的數(shù)量和每個(gè)分區(qū)列的類型信息), * 而不包含特定的界限。 * * We store the opclass-declared input data types instead of the partition key * datatypes since the former rather than the latter are used to compare * partition bounds. Since partition key data types and the opclass declared * input data types are expected to be binary compatible (per ResolveOpClass), * both of those should have same byval and length properties. * 我們存儲(chǔ)opclass-declared的輸入數(shù)據(jù)類型,而不是分區(qū)鍵數(shù)據(jù)類型, * 因?yàn)榍罢哂糜诒容^分區(qū)邊界,而不是后者。 * 由于分區(qū)鍵數(shù)據(jù)類型和opclass-declared的輸入數(shù)據(jù)類型預(yù)期是二進(jìn)制兼容的(每個(gè)ResolveOpClass), * 所以它們應(yīng)該具有相同的byval和length屬性。 */ typedef struct PartitionSchemeData { char strategy; /* 分區(qū)策略;partition strategy */ int16 partnatts; /* 分區(qū)屬性個(gè)數(shù);number of partition attributes */ Oid *partopfamily; /* 操作符族OIDs;OIDs of operator families */ Oid *partopcintype; /* opclass聲明的輸入數(shù)據(jù)類型的OIDs;OIDs of opclass declared input data types */ Oid *partcollation; /* 分區(qū)排序規(guī)則OIDs;OIDs of partitioning collations */ /* Cached information about partition key data types. */ //緩存有關(guān)分區(qū)鍵數(shù)據(jù)類型的信息。 int16 *parttyplen; bool *parttypbyval; /* Cached information about partition comparison functions. */ //緩存有關(guān)分區(qū)比較函數(shù)的信息。 FmgrInfo *partsupfunc; } PartitionSchemeData; typedef struct PartitionSchemeData *PartitionScheme;
PartitionPruneXXX
執(zhí)行Prune期間需要使用的數(shù)據(jù)結(jié)構(gòu),包括PartitionPruneStep/PartitionPruneStepOp/PartitionPruneCombineOp/PartitionPruneStepCombine
/* * Abstract Node type for partition pruning steps (there are no concrete * Nodes of this type). * 用于分區(qū)修剪步驟pruning的抽象節(jié)點(diǎn)類型(沒(méi)有這種類型的具體節(jié)點(diǎn))。 * * step_id is the global identifier of the step within its pruning context. * step_id是步驟在其修剪pruning上下文中的全局標(biāo)識(shí)符。 */ typedef struct PartitionPruneStep { NodeTag type; int step_id; } PartitionPruneStep; /* * PartitionPruneStepOp - Information to prune using a set of mutually AND'd * OpExpr clauses * PartitionPruneStepOp - 使用一組AND操作的OpExpr條件子句進(jìn)行修剪prune的信息 * * This contains information extracted from up to partnatts OpExpr clauses, * where partnatts is the number of partition key columns. 'opstrategy' is the * strategy of the operator in the clause matched to the last partition key. * 'exprs' contains expressions which comprise the lookup key to be passed to * the partition bound search function. 'cmpfns' contains the OIDs of * comparison functions used to compare aforementioned expressions with * partition bounds. Both 'exprs' and 'cmpfns' contain the same number of * items, up to partnatts items. * 它包含從partnatts OpExpr子句中提取的信息, * 其中partnatts是分區(qū)鍵列的數(shù)量。 * “opstrategy”是子句中與最后一個(gè)分區(qū)鍵匹配的操作符的策略。 * 'exprs'包含一些表達(dá)式,這些表達(dá)式包含要傳遞給分區(qū)綁定搜索函數(shù)的查找鍵。 * “cmpfns”包含用于比較上述表達(dá)式與分區(qū)邊界的比較函數(shù)的OIDs。 * “exprs”和“cmpfns”包含相同數(shù)量的條目,最多包含partnatts個(gè)條目。 * * Once we find the offset of a partition bound using the lookup key, we * determine which partitions to include in the result based on the value of * 'opstrategy'. For example, if it were equality, we'd return just the * partition that would contain that key or a set of partitions if the key * didn't consist of all partitioning columns. For non-equality strategies, * we'd need to include other partitions as appropriate. * 一旦我們使用查找鍵找到分區(qū)綁定的偏移量, * 我們將根據(jù)“opstrategy”的值確定在結(jié)果中包含哪些分區(qū)。 * 例如,如果它是相等的,我們只返回包含該鍵的分區(qū),或者如果該鍵不包含所有分區(qū)列, * 則返回一組分區(qū)。 * 對(duì)于非等值的情況,需要適當(dāng)?shù)匕ㄆ渌謪^(qū)。 * * 'nullkeys' is the set containing the offset of the partition keys (0 to * partnatts - 1) that were matched to an IS NULL clause. This is only * considered for hash partitioning as we need to pass which keys are null * to the hash partition bound search function. It is never possible to * have an expression be present in 'exprs' for a given partition key and * the corresponding bit set in 'nullkeys'. * 'nullkeys'是包含與is NULL子句匹配的分區(qū)鍵(0到partnatts - 1)偏移量的集合。 * 這只適用于哈希分區(qū),因?yàn)槲覀冃枰獙⒛男╂I為null傳遞給哈希分區(qū)綁定搜索函數(shù)。 * 對(duì)于給定的分區(qū)鍵和“nullkeys”中設(shè)置的相應(yīng)bit,不可能在“exprs”中出現(xiàn)表達(dá)式。 */ typedef struct PartitionPruneStepOp { PartitionPruneStep step; StrategyNumber opstrategy; List *exprs; List *cmpfns; Bitmapset *nullkeys; } PartitionPruneStepOp; /* * PartitionPruneStepCombine - Information to prune using a BoolExpr clause * PartitionPruneStepCombine - 使用BoolExpr條件prune的信息 * * For BoolExpr clauses, we combine the set of partitions determined for each * of the argument clauses. * 對(duì)于BoolExpr子句,我們?yōu)槊總€(gè)參數(shù)子句確定的分區(qū)集進(jìn)行組合。 */ typedef enum PartitionPruneCombineOp { PARTPRUNE_COMBINE_UNION, PARTPRUNE_COMBINE_INTERSECT } PartitionPruneCombineOp; typedef struct PartitionPruneStepCombine { PartitionPruneStep step; PartitionPruneCombineOp combineOp; List *source_stepids; } PartitionPruneStepCombine; /* The result of performing one PartitionPruneStep */ //執(zhí)行PartitionPruneStep步驟后的結(jié)果 typedef struct PruneStepResult { /* * The offsets of bounds (in a table's boundinfo) whose partition is * selected by the pruning step. * 被pruning步驟選中的分區(qū)邊界(在數(shù)據(jù)表boundinfo中)偏移 */ Bitmapset *bound_offsets; bool scan_default; /* 是否掃描默認(rèn)分區(qū)? Scan the default partition? */ bool scan_null; /* 是否為NULL值掃描分區(qū)? Scan the partition for NULL values? */ } PruneStepResult;
get_matching_partitions函數(shù)確定在分區(qū)pruning后仍然"存活"的分區(qū)。
/* * get_matching_partitions * Determine partitions that survive partition pruning * 確定在分區(qū)修剪pruning后仍然存在的分區(qū). * * Returns a Bitmapset of the RelOptInfo->part_rels indexes of the surviving * partitions. * 返回pruning后仍存在的分區(qū)的RelOptInfo->part_rels索引位圖集。 */ Bitmapset * get_matching_partitions(PartitionPruneContext *context, List *pruning_steps) { Bitmapset *result; int num_steps = list_length(pruning_steps), i; PruneStepResult **results, *final_result; ListCell *lc; /* If there are no pruning steps then all partitions match. */ //沒(méi)有pruning步驟,則視為保留所有分區(qū) if (num_steps == 0) { Assert(context->nparts > 0); return bms_add_range(NULL, 0, context->nparts - 1); } /* * Allocate space for individual pruning steps to store its result. Each * slot will hold a PruneStepResult after performing a given pruning step. * Later steps may use the result of one or more earlier steps. The * result of applying all pruning steps is the value contained in the slot * of the last pruning step. * 為單個(gè)修剪步驟分配空間來(lái)存儲(chǔ)結(jié)果。 * 每個(gè)slot將持有pruning后,執(zhí)行一個(gè)給定的pruning步驟。 * 后面的步驟可以使用前面一個(gè)或多個(gè)步驟的結(jié)果。 * 應(yīng)用所有步驟的結(jié)果是最后一個(gè)步驟的slot中包含的值。 */ results = (PruneStepResult **) palloc0(num_steps * sizeof(PruneStepResult *)); foreach(lc, pruning_steps)//遍歷步驟 { PartitionPruneStep *step = lfirst(lc); switch (nodeTag(step)) { case T_PartitionPruneStepOp: results[step->step_id] = perform_pruning_base_step(context, (PartitionPruneStepOp *) step);//執(zhí)行pruning基礎(chǔ)步驟 break; case T_PartitionPruneStepCombine: results[step->step_id] = perform_pruning_combine_step(context, (PartitionPruneStepCombine *) step, results);//執(zhí)行pruning組合步驟 break; default: elog(ERROR, "invalid pruning step type: %d", (int) nodeTag(step)); } } /* * At this point we know the offsets of all the datums whose corresponding * partitions need to be in the result, including special null-accepting * and default partitions. Collect the actual partition indexes now. * 到目前為止,我們已經(jīng)知道結(jié)果中需要的相應(yīng)分區(qū)的所有數(shù)據(jù)的偏移量, * 包括特殊的接受null的分區(qū)和默認(rèn)分區(qū)。 * 現(xiàn)在收集實(shí)際的分區(qū)索引。 */ final_result = results[num_steps - 1];//最終結(jié)果 Assert(final_result != NULL); i = -1; result = NULL; while ((i = bms_next_member(final_result->bound_offsets, i)) >= 0) { int partindex = context->boundinfo->indexes[i];//分區(qū)編號(hào) /* * In range and hash partitioning cases, some slots may contain -1, * indicating that no partition has been defined to accept a given * range of data or for a given remainder, respectively. The default * partition, if any, in case of range partitioning, will be added to * the result, because the specified range still satisfies the query's * conditions. * 范圍分區(qū)和散列分區(qū),一些slot可能包含-1, * 這表示沒(méi)有定義接受給定范圍的數(shù)據(jù)或給定余數(shù)的分區(qū)。 * 在范圍分區(qū)的情況下,默認(rèn)分區(qū)(如果有的話)將被添加到結(jié)果中, * 因?yàn)橹付ǖ姆秶匀粷M足查詢的條件。 */ if (partindex >= 0) result = bms_add_member(result, partindex); } /* Add the null and/or default partition if needed and if present. */ //如果需要,添加NULL和/或默認(rèn)分區(qū)。 if (final_result->scan_null) { Assert(context->strategy == PARTITION_STRATEGY_LIST); Assert(partition_bound_accepts_nulls(context->boundinfo)); result = bms_add_member(result, context->boundinfo->null_index); } if (final_result->scan_default) { Assert(context->strategy == PARTITION_STRATEGY_LIST || context->strategy == PARTITION_STRATEGY_RANGE); Assert(partition_bound_has_default(context->boundinfo)); result = bms_add_member(result, context->boundinfo->default_index); } return result; } /* * perform_pruning_base_step * Determines the indexes of datums that satisfy conditions specified in * 'opstep'. * 確定滿足“opstep”中指定條件的數(shù)據(jù)索引。 * * Result also contains whether special null-accepting and/or default * partition need to be scanned. * 結(jié)果還包含是否需要掃描特殊的可接受null和/或默認(rèn)分區(qū)。 */ static PruneStepResult * perform_pruning_base_step(PartitionPruneContext *context, PartitionPruneStepOp *opstep) { ListCell *lc1, *lc2; int keyno, nvalues; Datum values[PARTITION_MAX_KEYS]; FmgrInfo *partsupfunc; int stateidx; /* * There better be the same number of expressions and compare functions. * 最好有相同數(shù)量的表達(dá)式和比較函數(shù)。 */ Assert(list_length(opstep->exprs) == list_length(opstep->cmpfns)); nvalues = 0; lc1 = list_head(opstep->exprs); lc2 = list_head(opstep->cmpfns); /* * Generate the partition lookup key that will be used by one of the * get_matching_*_bounds functions called below. * 生成將由下面調(diào)用的get_matching_*_bounds函數(shù)使用的分區(qū)查找鍵。 */ for (keyno = 0; keyno < context->partnatts; keyno++) { /* * For hash partitioning, it is possible that values of some keys are * not provided in operator clauses, but instead the planner found * that they appeared in a IS NULL clause. * 對(duì)于哈希分區(qū),操作符子句中可能沒(méi)有提供某些鍵的值, * 但是計(jì)劃器發(fā)現(xiàn)它們出現(xiàn)在is NULL子句中。 */ if (bms_is_member(keyno, opstep->nullkeys)) continue; /* * For range partitioning, we must only perform pruning with values * for either all partition keys or a prefix thereof. * 對(duì)于范圍分區(qū),我們必須只對(duì)所有分區(qū)鍵或其前綴執(zhí)行值修剪pruning。 */ if (keyno > nvalues && context->strategy == PARTITION_STRATEGY_RANGE) break; if (lc1 != NULL)//步驟的條件表達(dá)式不為NULL { Expr *expr; Datum datum; bool isnull; expr = lfirst(lc1); stateidx = PruneCxtStateIdx(context->partnatts, opstep->step.step_id, keyno); if (partkey_datum_from_expr(context, expr, stateidx, &datum, &isnull)) { Oid cmpfn; /* * Since we only allow strict operators in pruning steps, any * null-valued comparison value must cause the comparison to * fail, so that no partitions could match. * 由于我們只允許在修剪pruning步驟中使用嚴(yán)格的操作符, * 任何空值比較值都必須導(dǎo)致比較失敗,這樣就沒(méi)有分區(qū)能夠匹配。 */ if (isnull) { PruneStepResult *result; result = (PruneStepResult *) palloc(sizeof(PruneStepResult)); result->bound_offsets = NULL; result->scan_default = false; result->scan_null = false; return result; } /* Set up the stepcmpfuncs entry, unless we already did */ //配置stepcmpfuncs(步驟比較函數(shù))入口 cmpfn = lfirst_oid(lc2); Assert(OidIsValid(cmpfn)); if (cmpfn != context->stepcmpfuncs[stateidx].fn_oid) { /* * If the needed support function is the same one cached * in the relation's partition key, copy the cached * FmgrInfo. Otherwise (i.e., when we have a cross-type * comparison), an actual lookup is required. * 如果所需的支持函數(shù)與關(guān)系分區(qū)鍵緩存的支持函數(shù)相同, * 則復(fù)制緩存的FmgrInfo。 * 否則(比如存在一個(gè)跨類型比較時(shí)),需要實(shí)際的查找。 */ if (cmpfn == context->partsupfunc[keyno].fn_oid) fmgr_info_copy(&context->stepcmpfuncs[stateidx], &context->partsupfunc[keyno], context->ppccontext); else fmgr_info_cxt(cmpfn, &context->stepcmpfuncs[stateidx], context->ppccontext); } values[keyno] = datum; nvalues++; } lc1 = lnext(lc1); lc2 = lnext(lc2); } } /* * Point partsupfunc to the entry for the 0th key of this step; the * additional support functions, if any, follow consecutively. * 將partsupfunc指向此步驟第0個(gè)鍵的條目; * 附加的支持功能(如果有的話)是連續(xù)的。 */ stateidx = PruneCxtStateIdx(context->partnatts, opstep->step.step_id, 0); partsupfunc = &context->stepcmpfuncs[stateidx]; switch (context->strategy) { case PARTITION_STRATEGY_HASH: return get_matching_hash_bounds(context, opstep->opstrategy, values, nvalues, partsupfunc, opstep->nullkeys); case PARTITION_STRATEGY_LIST: return get_matching_list_bounds(context, opstep->opstrategy, values[0], nvalues, &partsupfunc[0], opstep->nullkeys); case PARTITION_STRATEGY_RANGE: return get_matching_range_bounds(context, opstep->opstrategy, values, nvalues, partsupfunc, opstep->nullkeys); default: elog(ERROR, "unexpected partition strategy: %d", (int) context->strategy); break; } return NULL; } /* * perform_pruning_combine_step * Determines the indexes of datums obtained by combining those given * by the steps identified by cstep->source_stepids using the specified * combination method * 使用指定的組合方法將cstep->source_stepids標(biāo)識(shí)的步驟組合在一起得到數(shù)據(jù)索引 * * Since cstep may refer to the result of earlier steps, we also receive * step_results here. * 因?yàn)閏step可能引用前面步驟的結(jié)果,所以在這里也會(huì)收到step_results。 */ static PruneStepResult * perform_pruning_combine_step(PartitionPruneContext *context, PartitionPruneStepCombine *cstep, PruneStepResult **step_results) { ListCell *lc1; PruneStepResult *result = NULL; bool firststep; /* * A combine step without any source steps is an indication to not perform * any partition pruning, we just return all partitions. * 如無(wú)源步驟,則不執(zhí)行分區(qū)pruning,返回所有分區(qū) */ result = (PruneStepResult *) palloc0(sizeof(PruneStepResult)); if (list_length(cstep->source_stepids) == 0) { PartitionBoundInfo boundinfo = context->boundinfo; result->bound_offsets = bms_add_range(NULL, 0, boundinfo->ndatums - 1); result->scan_default = partition_bound_has_default(boundinfo); result->scan_null = partition_bound_accepts_nulls(boundinfo); return result; } switch (cstep->combineOp)//根據(jù)組合操作類型確定相應(yīng)邏輯 { case PARTPRUNE_COMBINE_UNION://PARTPRUNE_COMBINE_UNION foreach(lc1, cstep->source_stepids) { int step_id = lfirst_int(lc1); PruneStepResult *step_result; /* * step_results[step_id] must contain a valid result, which is * confirmed by the fact that cstep's step_id is greater than * step_id and the fact that results of the individual steps * are evaluated in sequence of their step_ids. * step_results[step_id]必須包含一個(gè)有效的結(jié)果, * cstep的step_id大于step_id,并且各個(gè)步驟的結(jié)果按其step_id的順序計(jì)算, * 這一點(diǎn)是可以確認(rèn)的。 */ if (step_id >= cstep->step.step_id) elog(ERROR, "invalid pruning combine step argument"); step_result = step_results[step_id]; Assert(step_result != NULL); /* Record any additional datum indexes from this step */ //記錄從該步驟產(chǎn)生的偏移索引 result->bound_offsets = bms_add_members(result->bound_offsets, step_result->bound_offsets); /* Update whether to scan null and default partitions. */ //更新掃描null/default分區(qū)的標(biāo)記 if (!result->scan_null) result->scan_null = step_result->scan_null; if (!result->scan_default) result->scan_default = step_result->scan_default; } break; case PARTPRUNE_COMBINE_INTERSECT://PARTPRUNE_COMBINE_INTERSECT firststep = true; foreach(lc1, cstep->source_stepids) { int step_id = lfirst_int(lc1); PruneStepResult *step_result; if (step_id >= cstep->step.step_id) elog(ERROR, "invalid pruning combine step argument"); step_result = step_results[step_id]; Assert(step_result != NULL); if (firststep)//第一個(gè)步驟 { /* Copy step's result the first time. */ //第一次,拷貝步驟的結(jié)果 result->bound_offsets = bms_copy(step_result->bound_offsets); result->scan_null = step_result->scan_null; result->scan_default = step_result->scan_default; firststep = false; } else { /* Record datum indexes common to both steps */ //記錄其他步驟產(chǎn)生的索引 result->bound_offsets = bms_int_members(result->bound_offsets, step_result->bound_offsets); /* Update whether to scan null and default partitions. */ //更新掃描null/default分區(qū)的標(biāo)記 if (result->scan_null) result->scan_null = step_result->scan_null; if (result->scan_default) result->scan_default = step_result->scan_default; } } break; } return result; } /* * get_matching_hash_bounds * Determine offset of the hash bound matching the specified values, * considering that all the non-null values come from clauses containing * a compatible hash equality operator and any keys that are null come * from an IS NULL clause. * 考慮到所有非空值都來(lái)自包含兼容的哈希相等操作符的子句, * 而所有空鍵都來(lái)自IS NULL子句,因此確定匹配指定值的哈希邊界的偏移量。 * * Generally this function will return a single matching bound offset, * although if a partition has not been setup for a given modulus then we may * return no matches. If the number of clauses found don't cover the entire * partition key, then we'll need to return all offsets. * 通常,這個(gè)函數(shù)會(huì)返回一個(gè)匹配的邊界偏移量, * 但是如果沒(méi)有為給定的模數(shù)設(shè)置分區(qū),則可能不返回匹配值。 * 如果找到的子句數(shù)量不包含整個(gè)分區(qū)鍵,那么我們需要返回所有偏移量。 * * 'opstrategy' if non-zero must be HTEqualStrategyNumber. * opstrategy - 如非0,則為HTEqualStrategyNumber * * 'values' contains Datums indexed by the partition key to use for pruning. * values 包含用于分區(qū)鍵執(zhí)行pruning的數(shù)據(jù)值 * * 'nvalues', the number of Datums in the 'values' array. * nvalues values數(shù)組大小 * * 'partsupfunc' contains partition hashing functions that can produce correct * hash for the type of the values contained in 'values'. * partsupfunc 存儲(chǔ)分區(qū)hash函數(shù),可以為values產(chǎn)生hash值 * * 'nullkeys' is the set of partition keys that are null. * nullkeys 為null的分區(qū)鍵值集合 */ static PruneStepResult * get_matching_hash_bounds(PartitionPruneContext *context, StrategyNumber opstrategy, Datum *values, int nvalues, FmgrInfo *partsupfunc, Bitmapset *nullkeys) { PruneStepResult *result = (PruneStepResult *) palloc0(sizeof(PruneStepResult)); PartitionBoundInfo boundinfo = context->boundinfo; int *partindices = boundinfo->indexes; int partnatts = context->partnatts; bool isnull[PARTITION_MAX_KEYS]; int i; uint64 rowHash; int greatest_modulus; Assert(context->strategy == PARTITION_STRATEGY_HASH); /* * For hash partitioning we can only perform pruning based on equality * clauses to the partition key or IS NULL clauses. We also can only * prune if we got values for all keys. * 對(duì)于Hash分區(qū),只能基于等值條件語(yǔ)句或者是IS NULL條件進(jìn)行pruning. * 當(dāng)然,如果可以拿到所有鍵的值,也可以執(zhí)行prune */ if (nvalues + bms_num_members(nullkeys) == partnatts) { /* * If there are any values, they must have come from clauses * containing an equality operator compatible with hash partitioning. * 如存在values,那么這些值必須從包含一個(gè)與hash分區(qū)兼容的等值操作符的條件語(yǔ)句而來(lái) */ Assert(opstrategy == HTEqualStrategyNumber || nvalues == 0); for (i = 0; i < partnatts; i++) isnull[i] = bms_is_member(i, nullkeys); greatest_modulus = get_hash_partition_greatest_modulus(boundinfo); rowHash = compute_partition_hash_value(partnatts, partsupfunc, values, isnull); if (partindices[rowHash % greatest_modulus] >= 0) result->bound_offsets = bms_make_singleton(rowHash % greatest_modulus); } else { /* Getting here means at least one hash partition exists. */ //程序執(zhí)行到這里,意味著至少存在一個(gè)hash分區(qū) Assert(boundinfo->ndatums > 0); result->bound_offsets = bms_add_range(NULL, 0, boundinfo->ndatums - 1); } /* * There is neither a special hash null partition or the default hash * partition. * 要么存在一個(gè)特別的hash null分區(qū),要么是默認(rèn)的hash分區(qū) */ result->scan_null = result->scan_default = false; return result; }
測(cè)試腳本如下
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)
啟動(dòng)gdb,設(shè)置斷點(diǎn)
(gdb) b get_matching_partitions Breakpoint 1 at 0x804d3b: file partprune.c, line 619. (gdb) c Continuing. Breakpoint 1, get_matching_partitions (context=0x7fff4a5e3930, pruning_steps=0x14d5300) at partprune.c:619 619 int num_steps = list_length(pruning_steps), (gdb) n 626 if (num_steps == 0)
查看輸入?yún)?shù),pruning_steps是有3個(gè)ITEM的鏈表
(gdb) p *pruning_steps $1 = {type = T_List, length = 3, head = 0x14d52d8, tail = 0x14d58d0}
pruning_steps的3個(gè)ITEM類型分別是PartitionPruneStepOp/PartitionPruneStepOp/PartitionPruneStepCombine
第1和2個(gè)ITEM的expr是Const,即常量1和2
(gdb) p *(Node *)pruning_steps->head->data.ptr_value $2 = {type = T_PartitionPruneStepOp} -->Node類型 (gdb) p *(PartitionPruneStepOp *)pruning_steps->head->data.ptr_value $3 = {step = {type = T_PartitionPruneStepOp, step_id = 0}, opstrategy = 1, exprs = 0x14d52a0, cmpfns = 0x14d5240, nullkeys = 0x0} (gdb) set $ppso=(PartitionPruneStepOp *)pruning_steps->head->data.ptr_value (gdb) p *$ppso->exprs $4 = {type = T_List, length = 1, head = 0x14d5278, tail = 0x14d5278} (gdb) p *(Node *)$ppso->exprs->head->data.ptr_value $5 = {type = T_Const} (gdb) p *(Const *)$ppso->exprs->head->data.ptr_value $6 = {xpr = {type = T_Const}, consttype = 23, consttypmod = -1, constcollid = 0, constlen = 4, constvalue = 1, constisnull = false, constbyval = true, location = 42} -->第1個(gè)步驟的表達(dá)式,常量1 (gdb) set $ppso=(PartitionPruneStepOp *)pruning_steps->head->next->data.ptr_value (gdb) p *(Const *)$ppso->exprs->head->data.ptr_value $7 = {xpr = {type = T_Const}, consttype = 23, consttypmod = -1, constcollid = 0, constlen = 4, constvalue = 2, constisnull = false, constbyval = true, location = 52} -->第2個(gè)步驟的表達(dá)式,常量2 (gdb) p *(Node *)pruning_steps->head->next->next->data.ptr_value $8 = {type = T_PartitionPruneStepCombine} (gdb) set $ppsc=(PartitionPruneStepCombine *)pruning_steps->head->next->next->data.ptr_value (gdb) p *$ppsc $9 = {step = {type = T_PartitionPruneStepCombine, step_id = 2}, combineOp = PARTPRUNE_COMBINE_UNION, source_stepids = 0x14d5480} -->第3個(gè)步驟,組合操作是PARTPRUNE_COMBINE_UNION
為步驟結(jié)果分配內(nèi)存
(gdb) n 640 palloc0(num_steps * sizeof(PruneStepResult *)); (gdb) p num_steps $10 = 3 (gdb) n 639 results = (PruneStepResult **) (gdb) 641 foreach(lc, pruning_steps)
開(kāi)始遍歷pruning步驟,進(jìn)入perform_pruning_base_step函數(shù)
(gdb) 643 PartitionPruneStep *step = lfirst(lc); (gdb) 645 switch (nodeTag(step)) (gdb) 648 results[step->step_id] = (gdb) step 649 perform_pruning_base_step(context, (gdb) perform_pruning_base_step (context=0x7fff4a5e3930, opstep=0x14d4e98) at partprune.c:2995 2995 Assert(list_length(opstep->exprs) == list_length(opstep->cmpfns));
perform_pruning_base_step->查看輸入?yún)?shù),比較函數(shù)是OID=425的函數(shù)
(gdb) p *opstep->cmpfns $12 = {type = T_OidList, length = 1, head = 0x14d5218, tail = 0x14d5218} (gdb) p opstep->cmpfns->head->data.oid_value $16 = 425 (gdb) n 2998 lc1 = list_head(opstep->exprs); (gdb) 2999 lc2 = list_head(opstep->cmpfns); (gdb)
perform_pruning_base_step->遍歷分區(qū)鍵
(gdb) 3005 for (keyno = 0; keyno < context->partnatts; keyno++) (gdb) 3012 if (bms_is_member(keyno, opstep->nullkeys)) -->沒(méi)有null鍵 (gdb) 3019 if (keyno > nvalues && context->strategy == PARTITION_STRATEGY_RANGE) -->nvalues為0 (gdb) p nvalues $17 = 0 (gdb) n 3022 if (lc1 != NULL) (gdb) 3028 expr = lfirst(lc1); -->獲取步驟中的表達(dá)式,其實(shí)是常量1 (gdb) 3029 stateidx = PruneCxtStateIdx(context->partnatts, -->stateidx為0 (gdb) p *expr $18 = {type = T_Const} (gdb) p *(Const *)expr $19 = {xpr = {type = T_Const}, consttype = 23, consttypmod = -1, constcollid = 0, constlen = 4, constvalue = 1, constisnull = false, constbyval = true, location = 42} (gdb) n 3031 if (partkey_datum_from_expr(context, expr, stateidx, (gdb) p stateidx $20 = 0 (gdb) n 3041 if (isnull) -->非NULL (gdb) p isnull $21 = false
perform_pruning_base_step->獲取比較函數(shù)進(jìn)行處理
(gdb) n 3054 cmpfn = lfirst_oid(lc2); --> OID=425 (gdb) 3055 Assert(OidIsValid(cmpfn)); (gdb) 3056 if (cmpfn != context->stepcmpfuncs[stateidx].fn_oid) -->fn_oid為0 (gdb) 3064 if (cmpfn == context->partsupfunc[keyno].fn_oid) -->fn_oid為425 (gdb) p context->stepcmpfuncs[stateidx].fn_oid $22 = 0 (gdb) p context->partsupfunc[keyno].fn_oid $23 = 425 (gdb) n 3065 fmgr_info_copy(&context->stepcmpfuncs[stateidx], (gdb) 3066 &context->partsupfunc[keyno], (gdb) 3065 fmgr_info_copy(&context->stepcmpfuncs[stateidx], (gdb) 3066 &context->partsupfunc[keyno], (gdb) 3065 fmgr_info_copy(&context->stepcmpfuncs[stateidx], --> 拷貝函數(shù) (gdb) 3073 values[keyno] = datum;-->設(shè)置值 (gdb) p datum $24 = 1 (gdb) n 3074 nvalues++; (gdb) 3077 lc1 = lnext(lc1); (gdb) 3078 lc2 = lnext(lc2); (gdb)
perform_pruning_base_step->完成分區(qū)鍵遍歷
(gdb) n 3005 for (keyno = 0; keyno < context->partnatts; keyno++) (gdb) 3086 stateidx = PruneCxtStateIdx(context->partnatts, opstep->step.step_id, 0); (gdb) 3087 partsupfunc = &context->stepcmpfuncs[stateidx]; (gdb) 3089 switch (context->strategy) (gdb) 3092 return get_matching_hash_bounds(context, (gdb)
perform_pruning_base_step->進(jìn)入get_matching_hash_bounds函數(shù)
(gdb) 3092 return get_matching_hash_bounds(context, (gdb) step 3093 opstep->opstrategy, (gdb) 3092 return get_matching_hash_bounds(context, (gdb) get_matching_hash_bounds (context=0x7fff4a5e3930, opstrategy=1, values=0x7fff4a5e3750, nvalues=1, partsupfunc=0x14d3068, nullkeys=0x0) at partprune.c:2156 2156 PruneStepResult *result = (PruneStepResult *) palloc0(sizeof(PruneStepResult)); (gdb)
get_matching_hash_bounds->變量賦值
(gdb) n 2157 PartitionBoundInfo boundinfo = context->boundinfo; (gdb) 2158 int *partindices = boundinfo->indexes; (gdb) 2159 int partnatts = context->partnatts; (gdb) 2165 Assert(context->strategy == PARTITION_STRATEGY_HASH); (gdb) 2172 if (nvalues + bms_num_members(nullkeys) == partnatts) (gdb)
get_matching_hash_bounds->分區(qū)邊界信息,共有6個(gè)分區(qū),Index分別是0-5
(gdb) p boundinfo $25 = (PartitionBoundInfo) 0x14d32a0 (gdb) p *boundinfo $26 = {strategy = 104 'h', ndatums = 6, datums = 0x14d32f8, kind = 0x0, indexes = 0x14d2e00, null_index = -1, default_index = -1} (gdb) p *boundinfo->datums $27 = (Datum *) 0x14d3350 (gdb) p **boundinfo->datums $28 = 6 (gdb) p **boundinfo->indexes Cannot access memory at address 0x0 (gdb) p *boundinfo->indexes $29 = 0 (gdb) p boundinfo->indexes[0] $30 = 0 (gdb) p boundinfo->indexes[1] $31 = 1 (gdb) p boundinfo->indexes[5] $32 = 5 (gdb)
get_matching_hash_bounds->分區(qū)索引和分區(qū)鍵數(shù)
(gdb) p *partindices $33 = 0 (gdb) p partnatts $34 = 1 (gdb) (gdb) p nvalues $35 = 1 (gdb) p bms_num_members(nullkeys) $36 = 0
get_matching_hash_bounds->遍歷分區(qū)鍵,判斷值是否落在分區(qū)中
(gdb) n 2178 Assert(opstrategy == HTEqualStrategyNumber || nvalues == 0); (gdb) 2180 for (i = 0; i < partnatts; i++) (gdb) 2181 isnull[i] = bms_is_member(i, nullkeys); (gdb) 2180 for (i = 0; i < partnatts; i++) (gdb) 2183 greatest_modulus = get_hash_partition_greatest_modulus(boundinfo); (gdb) 2184 rowHash = compute_partition_hash_value(partnatts, partsupfunc, (gdb) 2187 if (partindices[rowHash % greatest_modulus] >= 0)
get_matching_hash_bounds->
(gdb) p values $43 = (Datum *) 0x7fff4a5e3750 (gdb) p *values $44 = 1 --> 約束條件 (gdb) p isnull[0] $38 = false -->不為NULL (gdb) p greatest_modulus $39 = 6 -->6個(gè)分區(qū) (gdb) p rowHash $40 = 11274504255086170040 -->values算出的Hash值 (gdb) p rowHash % greatest_modulus $41 = 2 --> 所在的分區(qū) (gdb) p partindices[2] $42 = 2 -->存在該分區(qū) (gdb)
get_matching_hash_bounds->返回結(jié)果(bound_offsets->words=4,即編號(hào)2)
(gdb) n 2189 bms_make_singleton(rowHash % greatest_modulus); (gdb) 2188 result->bound_offsets = (gdb) 2203 result->scan_null = result->scan_default = false; (gdb) 2205 return result; (gdb) 2206 } (gdb) p *result $45 = {bound_offsets = 0x14d59b8, scan_default = false, scan_null = false} (gdb) p *result->bound_offsets $46 = {nwords = 1, words = 0x14d59bc} (gdb) p *result->bound_offsets->words $47 = 4 (gdb)
回到get_matching_partitions
(gdb) n perform_pruning_base_step (context=0x7fff4a5e3930, opstep=0x14d4e98) at partprune.c:3119 3119 } (gdb) get_matching_partitions (context=0x7fff4a5e3930, pruning_steps=0x14d5300) at partprune.c:648 648 results[step->step_id] = (gdb) 651 break; (gdb) 641 foreach(lc, pruning_steps) (gdb) 643 PartitionPruneStep *step = lfirst(lc); (gdb) 645 switch (nodeTag(step)) (gdb) p
繼續(xù)執(zhí)行步驟,進(jìn)入perform_pruning_combine_step
654 results[step->step_id] = (gdb) 655 perform_pruning_combine_step(context, (gdb) step perform_pruning_combine_step (context=0x7fff4a5e3930, cstep=0x14d5898, step_results=0x14d5958) at partprune.c:3136 3136 PruneStepResult *result = NULL; (gdb)
perform_pruning_combine_step->進(jìn)入PARTPRUNE_COMBINE_UNION處理邏輯
(gdb) n 3143 result = (PruneStepResult *) palloc0(sizeof(PruneStepResult)); (gdb) 3144 if (list_length(cstep->source_stepids) == 0) (gdb) 3154 switch (cstep->combineOp) (gdb) 3157 foreach(lc1, cstep->source_stepids) (gdb) (gdb) p *cstep $49 = {step = {type = T_PartitionPruneStepCombine, step_id = 2}, combineOp = PARTPRUNE_COMBINE_UNION, source_stepids = 0x14d5480}
perform_pruning_combine_step->遍歷組合步驟的源步驟 cstep->source_stepids,合并這些步驟的結(jié)果
(gdb) n 3159 int step_id = lfirst_int(lc1); ... (gdb) 3174 result->bound_offsets = bms_add_members(result->bound_offsets, (gdb) 3178 if (!result->scan_null) (gdb) 3179 result->scan_null = step_result->scan_null; (gdb) 3180 if (!result->scan_default) (gdb) 3181 result->scan_default = step_result->scan_default; (gdb) 3157 foreach(lc1, cstep->source_stepids) (gdb) 3183 break; (gdb) 3223 return result; (gdb)
perform_pruning_combine_step->最終結(jié)果
(gdb) p *result $54 = {bound_offsets = 0x14d5a48, scan_default = false, scan_null = false} (gdb) p *result->bound_offsets $55 = {nwords = 1, words = 0x14d5a4c} (gdb) p *result->bound_offsets->words $56 = 5
perform_pruning_combine_step->回到get_matching_partitions
(gdb) n 3224 } (gdb) get_matching_partitions (context=0x7fff4a5e3930, pruning_steps=0x14d5300) at partprune.c:654 654 results[step->step_id] =
完成所有步驟的處理
(gdb) n 658 break; (gdb) 641 foreach(lc, pruning_steps) (gdb) n 671 final_result = results[num_steps - 1]; (gdb) 672 Assert(final_result != NULL); (gdb)
構(gòu)造結(jié)果位圖集
... 675 while ((i = bms_next_member(final_result->bound_offsets, i)) >= 0) (gdb) n 677 int partindex = context->boundinfo->indexes[i]; (gdb) 687 if (partindex >= 0) (gdb) 688 result = bms_add_member(result, partindex); (gdb)
完成調(diào)用
gdb) 675 while ((i = bms_next_member(final_result->bound_offsets, i)) >= 0) (gdb) 692 if (final_result->scan_null) (gdb) 698 if (final_result->scan_default) (gdb) 706 return result; (gdb) 707 } (gdb)
關(guān)于“PostgreSQL中prune_append_rel_partitions->get_matching_partitions函數(shù)怎么用”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,使各位可以學(xué)到更多知識(shí),如果覺(jué)得文章不錯(cuò),請(qǐng)把它分享出去讓更多的人看到。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。