共计 8954 个字符,预计需要花费 23 分钟才能阅读完成。
行业资讯
数据库
关系型数据库
PostgreSQL 中 prune_append_rel_partitions- get_matching_partitions 函数怎么用
这篇文章将为大家详细讲解有关 PostgreSQL 中 prune_append_rel_partitions- get_matching_partitions 函数怎么用,丸趣 TV 小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。
一、数据结构
PartitionScheme
分区方案, 根据设计,分区方案只包含分区方法的一般属性(列表与范围、分区列的数量和每个分区列的类型信息),而不包含特定的分区边界信息。
/*
* 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.
* 如果多个关系以相同的方式分区,那么所有这些分区都将具有指向相同 PartitionScheme 的指针。 * PartitionScheme 对象的链表附加到 PlannerInfo 中。 * 根据设计,分区方案只包含分区方法的一般属性(列表与范围、分区列的数量和每个分区列的类型信息), * 而不包含特定的界限。 *
* 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.
* 我们存储 opclass-declared 的输入数据类型,而不是分区键数据类型, * 因为前者用于比较分区边界,而不是后者。 * 由于分区键数据类型和 opclass-declared 的输入数据类型预期是二进制兼容的(每个 ResolveOpClass), * 所以它们应该具有相同的 byval 和 length 属性。 */
typedef struct PartitionSchemeData
char strategy; /* 分区策略;partition strategy */
int16 partnatts; /* 分区属性个数;number of partition attributes */
Oid *partopfamily; /* 操作符族 OIDs;OIDs of operator families */
Oid *partopcintype; /* opclass 声明的输入数据类型的 OIDs;OIDs of opclass declared input data types */
Oid *partcollation; /* 分区排序规则 OIDs;OIDs of partitioning collations */
/* Cached information about partition key data types. */
// 缓存有关分区键数据类型的信息。 int16 *parttyplen;
bool *parttypbyval;
/* Cached information about partition comparison functions. */
// 缓存有关分区比较函数的信息。 FmgrInfo *partsupfunc;
} PartitionSchemeData;
typedef struct PartitionSchemeData *PartitionScheme;
PartitionPruneXXX
执行 Prune 期间需要使用的数据结构, 包括 PartitionPruneStep/PartitionPruneStepOp/PartitionPruneCombineOp/PartitionPruneStepCombine
/*
* Abstract Node type for partition pruning steps (there are no concrete
* Nodes of this type).
* 用于分区修剪步骤 pruning 的抽象节点类型(没有这种类型的具体节点)。 *
* step_id is the global identifier of the step within its pruning context.
* step_id 是步骤在其修剪 pruning 上下文中的全局标识符。 */
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 条件子句进行修剪 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 是分区键列的数量。 * “opstrategy”是子句中与最后一个分区键匹配的操作符的策略。 * exprs 包含一些表达式,这些表达式包含要传递给分区绑定搜索函数的查找键。 * “cmpfns”包含用于比较上述表达式与分区边界的比较函数的 OIDs。 * “exprs”和“cmpfns”包含相同数量的条目,最多包含 partnatts 个条目。 *
* 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.
* 一旦我们使用查找键找到分区绑定的偏移量, * 我们将根据“opstrategy”的值确定在结果中包含哪些分区。 * 例如,如果它是相等的,我们只返回包含该键的分区,或者如果该键不包含所有分区列, * 则返回一组分区。 * 对于非等值的情况,需要适当地包括其他分区。 *
* 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 子句匹配的分区键 (0 到 partnatts - 1) 偏移量的集合。 * 这只适用于哈希分区,因为我们需要将哪些键为 null 传递给哈希分区绑定搜索函数。 * 对于给定的分区键和“nullkeys”中设置的相应 bit,不可能在“exprs”中出现表达式。 */
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.
* 对于 BoolExpr 子句,我们为每个参数子句确定的分区集进行组合。 */
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 */
// 执行 PartitionPruneStep 步骤后的结果
typedef struct PruneStepResult
/*
* The offsets of bounds (in a table s boundinfo) whose partition is
* selected by the pruning step.
* 被 pruning 步骤选中的分区边界 (在数据表 boundinfo 中) 偏移
*/
Bitmapset *bound_offsets;
bool scan_default; /* 是否扫描默认分区? Scan the default partition? */
bool scan_null; /* 是否为 NULL 值扫描分区? Scan the partition for NULL values? */
} PruneStepResult;
二、源码解读
get_matching_partitions 函数确定在分区 pruning 后仍然 存活 的分区。
/*
* get_matching_partitions
* Determine partitions that survive partition pruning
* 确定在分区修剪 pruning 后仍然存在的分区.
*
* Returns a Bitmapset of the RelOptInfo- part_rels indexes of the surviving
* partitions.
* 返回 pruning 后仍存在的分区的 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. */
// 没有 pruning 步骤, 则视为保留所有分区
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.
* 为单个修剪步骤分配空间来存储结果。
* 每个 slot 将持有 pruning 后,执行一个给定的 pruning 步骤。
* 后面的步骤可以使用前面一个或多个步骤的结果。
* 应用所有步骤的结果是最后一个步骤的 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);// 执行 pruning 基础步骤
break;
case T_PartitionPruneStepCombine:
results[step- step_id] =
perform_pruning_combine_step(context,
(PartitionPruneStepCombine *) step,
results);// 执行 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.
* 到目前为止, 我们已经知道结果中需要的相应分区的所有数据的偏移量,
* 包括特殊的接受 null 的分区和默认分区。
* 现在收集实际的分区索引。
*/
final_result = results[num_steps - 1];// 最终结果
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];// 分区编号
/*
* 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.
* 范围分区和散列分区,一些 slot 可能包含 -1,
* 这表示没有定义接受给定范围的数据或给定余数的分区。
* 在范围分区的情况下,默认分区 (如果有的话) 将被添加到结果中,
* 因为指定的范围仍然满足查询的条件。
*/
if (partindex = 0)
result = bms_add_member(result, partindex);
}
/* Add the null and/or default partition if needed and if present. */
// 如果需要,添加 NULL 和 / 或默认分区。
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;
正文完
发表至: 数据库
2023-07-24