PostgreSQL在查询分区表时如何确定查询的是哪个分区
这篇文章给大家分享的是有关PostgreSQL在查询分区表时如何确定查询的是哪个分区的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。
在规划阶段,函数set_rel_size中,如RTE为分区表(rte->inh=T),则调用set_append_rel_size函数,在set_append_rel_size中通过prune_append_rel_partitions函数获取“仍存活”的分区,下面介绍了prune_append_rel_partitions函数的主逻辑和依赖的函数gen_partprune_steps。
一、数据结构
PartitionScheme
分区方案,根据设计,分区方案只包含分区方法的一般属性(列表与范围、分区列的数量和每个分区列的类型信息),而不包含特定的分区边界信息。
typedef struct PartitionSchemeData
{
char strategy;
int16 partnatts;
Oid *partopfamily;
Oid *partopcintype;
Oid *partcollation;
//缓存有关分区键数据类型的信息。
int16 *parttyplen;
bool *parttypbyval;
//缓存有关分区比较函数的信息。
FmgrInfo *partsupfunc;
} PartitionSchemeData;
typedef struct PartitionSchemeData *PartitionScheme;
PartitionPruneXXX
执行Prune期间需要使用的数据结构,包括PartitionPruneStep/PartitionPruneStepOp/PartitionPruneCombineOp/PartitionPruneStepCombine
typedef struct PartitionPruneStep
{
NodeTag type;
int step_id;
} PartitionPruneStep;
typedef struct PartitionPruneStepOp
{
PartitionPruneStep step;
StrategyNumber opstrategy;
List *exprs;
List *cmpfns;
Bitmapset *nullkeys;
} PartitionPruneStepOp;
typedef enum PartitionPruneCombineOp
{
PARTPRUNE_COMBINE_UNION,
PARTPRUNE_COMBINE_INTERSECT
} PartitionPruneCombineOp;
typedef struct PartitionPruneStepCombine
{
PartitionPruneStep step;
PartitionPruneCombineOp combineOp;
List *source_stepids;
} PartitionPruneStepCombine;
二、源码解读
prune_append_rel_partitions函数返回必须扫描以满足rel约束条件baserestrictinfo quals的最小子分区集的RT索引。
Relids
prune_append_rel_partitions(RelOptInfo *rel)
{
Relids result;
List *clauses = rel->baserestrictinfo;
List *pruning_steps;
bool contradictory;
PartitionPruneContext context;
Bitmapset *partindexes;
int i;
Assert(clauses != NIL);
Assert(rel->part_scheme != NULL);
//如无分区,则返回NULL
if (rel->nparts == 0)
return NULL;
pruning_steps = gen_partprune_steps(rel, clauses, &contradictory);
if (contradictory)
return NULL;
//配置PartitionPruneContext上下文
context.strategy = rel->part_scheme->strategy;
context.partnatts = rel->part_scheme->partnatts;
context.nparts = rel->nparts;
context.boundinfo = rel->boundinfo;
context.partcollation = rel->part_scheme->partcollation;
context.partsupfunc = rel->part_scheme->partsupfunc;
context.stepcmpfuncs = (FmgrInfo *) palloc0(sizeof(FmgrInfo) *
context.partnatts *
list_length(pruning_steps));
context.ppccontext = CurrentMemoryContext;
//如从规划器调用,这些状态变量为NULL
context.planstate = NULL;
context.exprstates = NULL;
context.exprhasexecparam = NULL;
context.evalexecparams = false;
//这是实现逻辑
partindexes = get_matching_partitions(&context, pruning_steps);
//把选中的分区RT索引放到结果中
i = -1;
result = NULL;
while ((i = bms_next_member(partindexes, i)) >= 0)
result = bms_add_member(result, rel->part_rels[i]->relid);
return result;
}
static List *
gen_partprune_steps(RelOptInfo *rel, List *clauses, bool *contradictory)
{
GeneratePruningStepsContext context;
context.next_step_id = 0;
context.steps = NIL;
//为确保安全,拷贝一份副本
clauses = list_copy(clauses);
if (partition_bound_has_default(rel->boundinfo) &&
rel->partition_qual != NIL)
{
List *partqual = rel->partition_qual;//分区条件链表
partqual = (List *) expression_planner((Expr *) partqual);
//修正Vars,以使其具备合适的编号varno
if (rel->relid != 1)
ChangeVarNodes((Node *) partqual, 1, rel->relid, 0);
clauses = list_concat(clauses, partqual);//添加到条件链表中
}
//进入到"兔子洞"中(实际生成步骤)
gen_partprune_steps_internal(&context, rel, clauses, contradictory);
return context.steps;
}
static List *
gen_partprune_steps_internal(GeneratePruningStepsContext *context,
RelOptInfo *rel, List *clauses,
bool *contradictory)
{
PartitionScheme part_scheme = rel->part_scheme;
List *keyclauses[PARTITION_MAX_KEYS];
Bitmapset *nullkeys = NULL,
*notnullkeys = NULL;
bool generate_opsteps = false;
List *result = NIL;
ListCell *lc;
*contradictory = false;
memset(keyclauses, 0, sizeof(keyclauses));
foreach(lc, clauses)
{
Expr *clause = (Expr *) lfirst(lc);
int i;
//RestrictInfo类型
if (IsA(clause, RestrictInfo))
clause = ((RestrictInfo *) clause)->clause;
//False或者是NULL,设置为互斥,返回NIL
if (IsA(clause, Const) &&
(((Const *) clause)->constisnull ||
!DatumGetBool(((Const *) clause)->constvalue)))
{
*contradictory = true;
return NIL;
}
//Bool表达式
if (IsA(clause, BoolExpr))
{
if (or_clause((Node *) clause))
{
//OR
List *arg_stepids = NIL;
bool all_args_contradictory = true;
ListCell *lc1;
foreach(lc1, ((BoolExpr *) clause)->args)//遍历条件参数
{
Expr *arg = lfirst(lc1);
bool arg_contradictory;
List *argsteps;
argsteps =
gen_partprune_steps_internal(context, rel,
list_make1(arg),
&arg_contradictory);
if (!arg_contradictory)
all_args_contradictory = false;
if (argsteps != NIL)
{
PartitionPruneStep *step;
Assert(list_length(argsteps) == 1);
step = (PartitionPruneStep *) linitial(argsteps);
arg_stepids = lappend_int(arg_stepids, step->step_id);
}
else
{
List *partconstr = rel->partition_qual;
PartitionPruneStep *orstep;
//忽略该参数
if (arg_contradictory)
continue;
if (partconstr)
{
partconstr = (List *)
expression_planner((Expr *) partconstr);
if (rel->relid != 1)
ChangeVarNodes((Node *) partconstr, 1,
rel->relid, 0);
if (predicate_refuted_by(partconstr,
list_make1(arg),
false))//没有匹配分区键
continue;
}
//构造PARTPRUNE_COMBINE_UNION步骤
orstep = gen_prune_step_combine(context, NIL,
PARTPRUNE_COMBINE_UNION);
//ID
arg_stepids = lappend_int(arg_stepids, orstep->step_id);
}
}
//输出参数赋值
*contradictory = all_args_contradictory;
//检查是否互斥,如是则返回NIL
if (*contradictory)
return NIL;
if (arg_stepids != NIL)
{
PartitionPruneStep *step;
//构造step
step = gen_prune_step_combine(context, arg_stepids,
PARTPRUNE_COMBINE_UNION);
result = lappend(result, step);
}
continue;
}
else if (and_clause((Node *) clause))
{
//AND
List *args = ((BoolExpr *) clause)->args;//参数链表
List *argsteps,
*arg_stepids = NIL;
ListCell *lc1;
argsteps = gen_partprune_steps_internal(context, rel, args,
contradictory);
if (*contradictory)
return NIL;//互斥,返回NIL
foreach(lc1, argsteps)//遍历步骤
{
PartitionPruneStep *step = lfirst(lc1);
arg_stepids = lappend_int(arg_stepids, step->step_id);
}
if (arg_stepids != NIL)//组合步骤
{
PartitionPruneStep *step;
step = gen_prune_step_combine(context, arg_stepids,
PARTPRUNE_COMBINE_INTERSECT);
result = lappend(result, step);
}
continue;
}
}
for (i = 0; i < part_scheme->partnatts; i++)
{
Expr *partkey = linitial(rel->partexprs[i]);//分区键
bool clause_is_not_null = false;
PartClauseInfo *pc = NULL;//分区条件信息
List *clause_steps = NIL;
//尝试将给定的“条件子句”与指定的分区键匹配。
switch (match_clause_to_partition_key(rel, context,
clause, partkey, i,
&clause_is_not_null,
&pc, &clause_steps))
{
//存在匹配项,输出参数为条件
case PARTCLAUSE_MATCH_CLAUSE:
Assert(pc != NULL);
if (bms_is_member(i, nullkeys))
{
*contradictory = true;
return NIL;
}
generate_opsteps = true;
keyclauses[i] = lappend(keyclauses[i], pc);
break;
//存在匹配项,匹配的子句是“a is NULL”或“a is NOT NULL”子句
case PARTCLAUSE_MATCH_NULLNESS:
if (!clause_is_not_null)
{
if (bms_is_member(i, notnullkeys))
{
*contradictory = true;
return NIL;
}
nullkeys = bms_add_member(nullkeys, i);
}
else
{
if (bms_is_member(i, nullkeys))
{
*contradictory = true;
return NIL;
}
notnullkeys = bms_add_member(notnullkeys, i);
}
break;
//存在匹配项,输出参数是步骤
case PARTCLAUSE_MATCH_STEPS:
Assert(clause_steps != NIL);
result = list_concat(result, clause_steps);
break;
case PARTCLAUSE_MATCH_CONTRADICT:
*contradictory = true;
return NIL;
//不存在匹配项
case PARTCLAUSE_NOMATCH:
continue;
//该子句不能用于pruning
case PARTCLAUSE_UNSUPPORTED:
break;
}
//完成一个子句的处理,继续下一个
break;
}
}
if (!bms_is_empty(nullkeys) &&
(part_scheme->strategy == PARTITION_STRATEGY_LIST ||
part_scheme->strategy == PARTITION_STRATEGY_RANGE ||
(part_scheme->strategy == PARTITION_STRATEGY_HASH &&
bms_num_members(nullkeys) == part_scheme->partnatts)))
{
PartitionPruneStep *step;
//策略1
step = gen_prune_step_op(context, InvalidStrategy,
false, NIL, NIL, nullkeys);
result = lappend(result, step);
}
else if (generate_opsteps)
{
PartitionPruneStep *step;
//策略2
step = gen_prune_steps_from_opexps(part_scheme, context,
keyclauses, nullkeys);
if (step != NULL)
result = lappend(result, step);
}
else if (bms_num_members(notnullkeys) == part_scheme->partnatts)
{
PartitionPruneStep *step;
//策略3
step = gen_prune_step_op(context, InvalidStrategy,
false, NIL, NIL, NULL);
result = lappend(result, step);
}
if (list_length(result) > 1)
{
List *step_ids = NIL;
foreach(lc, result)
{
PartitionPruneStep *step = lfirst(lc);
step_ids = lappend_int(step_ids, step->step_id);
}
if (step_ids != NIL)
{
PartitionPruneStep *step;
step = gen_prune_step_combine(context, step_ids,
PARTPRUNE_COMBINE_INTERSECT);
result = lappend(result, step);
}
}
return result;
}
三、跟踪分析
测试脚本如下
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)
启动gdb,设置断点
(gdb) b prune_append_rel_partitions
Breakpoint 1 at 0x804b07: file partprune.c, line 555.
(gdb) c
Continuing.
Breakpoint 1, prune_append_rel_partitions (rel=0x20faba0) at partprune.c:555
555 List *clauses = rel->baserestrictinfo;
获取约束条件
(gdb) n
562 Assert(clauses != NIL);
(gdb)
563 Assert(rel->part_scheme != NULL);
(gdb)
566 if (rel->nparts == 0)
(gdb)
573 pruning_steps = gen_partprune_steps(rel, clauses, &contradictory);
进入gen_partprune_steps
(gdb) step
gen_partprune_steps (rel=0x20faba0, clauses=0x21c4d20, contradictory=0x7ffe1953a8d7) at partprune.c:505
505 context.next_step_id = 0;
gen_partprune_steps->判断是否有默认分区(无)
(gdb) n
506 context.steps = NIL;
(gdb) n
509 clauses = list_copy(clauses);
(gdb)
524 if (partition_bound_has_default(rel->boundinfo) &&
(gdb)
gen_partprune_steps_internal->进入gen_partprune_steps_internal
(gdb) step
gen_partprune_steps_internal (context=0x7ffe1953a830, rel=0x20faba0, clauses=0x21c4e00, contradictory=0x7ffe1953a8d7)
at partprune.c:741
741 PartitionScheme part_scheme = rel->part_scheme;
gen_partprune_steps_internal->查看分区方案(PartitionScheme)
(gdb) n
743 Bitmapset *nullkeys = NULL,
(gdb) p *part_scheme
$1 = {strategy = 104 'h', partnatts = 1, partopfamily = 0x21c3180, partopcintype = 0x21c31a0, partcollation = 0x21c31c0,
parttyplen = 0x21c31e0, parttypbyval = 0x21c3200, partsupfunc = 0x21c3220}
(gdb) p *part_scheme->partopfamily
$2 = 1977
(gdb) p *part_scheme->partopcintype
$3 = 23
(gdb) p *part_scheme->partcollation
$4 = 0
(gdb) p *part_scheme->parttyplen
$5 = 4
(gdb) p *part_scheme->parttypbyval
$6 = true
(gdb) p *part_scheme->partsupfunc
$7 = {fn_addr = 0x4c85e7 <hashint4extended>, fn_oid = 425, fn_nargs = 2, fn_strict = true, fn_retset = false,
fn_stats = 2 '\002', fn_extra = 0x0, fn_mcxt = 0x20f8db0, fn_expr = 0x0}
gen_partprune_steps_internal->SQL查询结果
opfamily->integer_ops,整型操作
testdb=# select * from pg_opfamily where oid=1977;
opfmethod | opfname | opfnamespace | opfowner
-----------+-------------+--------------+----------
405 | integer_ops | 11 | 10
(1 row)
gen_partprune_steps_internal->初始化变量
(gdb) n
744 *notnullkeys = NULL;
(gdb)
745 bool generate_opsteps = false;
(gdb)
746 List *result = NIL;
(gdb)
749 *contradictory = false;
(gdb)
751 memset(keyclauses, 0, sizeof(keyclauses));
(gdb)
gen_partprune_steps_internal->循环处理条件子句
752 foreach(lc, clauses)
(gdb) n
754 Expr *clause = (Expr *) lfirst(lc);
(gdb) p *clauses
$8 = {type = T_List, length = 1, head = 0x21c4dd8, tail = 0x21c4dd8}
(gdb) p *clause
$9 = {type = T_RestrictInfo}
(gdb) n
759 clause = ((RestrictInfo *) clause)->clause;
(gdb)
762 if (IsA(clause, Const) &&
(gdb) p *clause
$10 = {type = T_BoolExpr}
gen_partprune_steps_internal->布尔表达式,进入相应的处理逻辑
(gdb) n
771 if (IsA(clause, BoolExpr))
(gdb)
781 if (or_clause((Node *) clause))
(gdb)
gen_partprune_steps_internal->OR子句,进入相应的实现逻辑
(gdb)
783 List *arg_stepids = NIL;
(gdb)
(gdb)
784 bool all_args_contradictory = true;
(gdb)
791 foreach(lc1, ((BoolExpr *) clause)->args)
(gdb)
793 Expr *arg = lfirst(lc1);
(gdb)
798 gen_partprune_steps_internal(context, rel,
(gdb)
gen_partprune_steps_internal->OR子句的相关信息
(gdb) p *((BoolExpr *) clause)->args
$3 = {type = T_List, length = 2, head = 0x21bf138, tail = 0x21bf198}
(gdb) p *(OpExpr *)arg
$4 = {xpr = {type = T_OpExpr}, opno = 96, opfuncid = 65, opresulttyp
gen_partprune_steps_internal->递归调用gen_partprune_steps_internal,返回argsteps链表
797 argsteps =
(gdb) n
801 if (!arg_contradictory)
(gdb)
802 all_args_contradictory = false;
(gdb)
804 if (argsteps != NIL)
(gdb)
808 Assert(list_length(argsteps) == 1);
(gdb) p argsteps
$6 = (List *) 0x21c29b0
(gdb) p *argsteps
$7 = {type = T_List, length = 1, head = 0x21c2988, tail = 0x21c2988}
(gdb) p *(Node *)argsteps->head->data.ptr_value
$8 = {type = T_PartitionPruneStepOp}
(gdb) p *(PartitionPruneStepOp *)argsteps->head->data.ptr_value
$9 = {step = {type = T_PartitionPruneStepOp, step_id = 0}, opstrategy = 1, exprs = 0x21c2830, cmpfns = 0x21c27d0,
nullkeys = 0x0}
gen_partprune_steps_internal->构造step,继续OR子句的下一个条件
(gdb) n
809 step = (PartitionPruneStep *) linitial(argsteps);
(gdb)
810 arg_stepids = lappend_int(arg_stepids, step->step_id);
(gdb)
(gdb)
791 foreach(lc1, ((BoolExpr *) clause)->args)
gen_partprune_steps_internal->递归调用gen_partprune_steps_internal,进入递归调用gen_partprune_steps_internal函数
(gdb) step
gen_partprune_steps_internal (context=0x7ffe1953a830, rel=0x20fab08, clauses=0x21c2a70, contradictory=0x7ffe1953a60f)
at partprune.c:741
741 PartitionScheme part_scheme = rel->part_scheme;
(gdb)
...
递归调用gen_partprune_steps_internal->遍历条件
752 foreach(lc, clauses)
(gdb)
754 Expr *clause = (Expr *) lfirst(lc);
(gdb)
758 if (IsA(clause, RestrictInfo))
(gdb) p *(Expr *)clause
$14 = {type = T_OpExpr}
(gdb) p *(OpExpr *)clause
$15 = {xpr = {type = T_OpExpr}, opno = 96, opfuncid = 65, opresulttype = 16, opretset = false, opcollid = 0,
inputcollid = 0, args = 0x21becf8, location = 50}
(gdb) n
762 if (IsA(clause, Const) &&
(gdb)
771 if (IsA(clause, BoolExpr))
(gdb)
918 for (i = 0; i < part_scheme->partnatts; i++)
递归调用gen_partprune_steps_internal->遍历分区方案
(gdb)
920 Expr *partkey = linitial(rel->partexprs[i]);
(gdb)
921 bool clause_is_not_null = false;
(gdb) p *(Expr *)partkey
$16 = {type = T_Var}
(gdb) p *(Var *)partkey
$17 = {xpr = {type = T_Var}, varno = 1, varattno = 1, vartype = 23, vartypmod = -1, varcollid = 0, varlevelsup = 0,
varnoold = 1, varoattno = 1, location = -1}
递归调用gen_partprune_steps_internal->尝试将给定的“条件子句”与指定的分区键匹配,match_clause_to_partition_key函数输出结果为PARTCLAUSE_MATCH_CLAUSE(存在匹配项,输出参数为条件)
(gdb) n
922 PartClauseInfo *pc = NULL;
(gdb)
923 List *clause_steps = NIL;
(gdb)
925 switch (match_clause_to_partition_key(rel, context,
(gdb)
931 Assert(pc != NULL);
(gdb)
937 if (bms_is_member(i, nullkeys))
942 generate_opsteps = true;
(gdb)
943 keyclauses[i] = lappend(keyclauses[i], pc);
(gdb)
944 break;
(gdb) p keyclauses[i]
$18 = (List *) 0x21c2b08
(gdb) p *keyclauses[i]
$19 = {type = T_List, length = 1, head = 0x21c2ae0, tail = 0x21c2ae0}
(gdb) p *(Node *)keyclauses[i]->head->data.ptr_value
$20 = {type = T_Invalid}
递归调用gen_partprune_steps_internal->完成条件遍历,开始生产pruning步骤,使用第2种策略(根据拥有的OpExprs生成步骤)生成
(gdb) n
752 foreach(lc, clauses)
(gdb) n
1019 if (!bms_is_empty(nullkeys) &&
(gdb)
1032 else if (generate_opsteps)
(gdb)
1037 step = gen_prune_steps_from_opexps(part_scheme, context,
(gdb) n
1039 if (step != NULL)
(gdb) p *step
$21 = {type = T_PartitionPruneStepOp, step_id = 1}
(gdb) n
1040 result = lappend(result, step);
(gdb)
1056 if (list_length(result) > 1)
(gdb) p *result
$22 = {type = T_List, length = 1, head = 0x21c2da0, tail = 0x21c2da0}
(gdb) n
1077 return result;
(gdb)
1078 }
(gdb)
gen_partprune_steps_internal->递归调用返回,完成OR子句的处理
(gdb)
801 if (!arg_contradictory)
(gdb)
802 all_args_contradictory = false;
(gdb)
804 if (argsteps != NIL)
(gdb)
808 Assert(list_length(argsteps) == 1);
(gdb)
809 step = (PartitionPruneStep *) linitial(argsteps);
(gdb)
810 arg_stepids = lappend_int(arg_stepids, step->step_id);
(gdb)
791 foreach(lc1, ((BoolExpr *) clause)->args)
(gdb)
(gdb)
855 *contradictory = all_args_contradictory;
(gdb)
858 if (*contradictory)
(gdb) p all_args_contradictory
$23 = false
(gdb) n
861 if (arg_stepids != NIL)
(gdb)
865 step = gen_prune_step_combine(context, arg_stepids,
(gdb)
867 result = lappend(result, step);
(gdb)
869 continue;
(gdb) p *step
$24 = {<text variable, no debug info>} 0x7f4522678be0 <__step>
(gdb) p *result
$25 = {type = T_List, length = 1, head = 0x21c2e88, tail = 0x21c2e88}
gen_partprune_steps_internal->完成所有条件子句的遍历,返回result
(gdb) n
752 foreach(lc, clauses)
(gdb)
1019 if (!bms_is_empty(nullkeys) &&
(gdb)
1032 else if (generate_opsteps)
(gdb)
1042 else if (bms_num_members(notnullkeys) == part_scheme->partnatts)
(gdb)
1056 if (list_length(result) > 1)
(gdb)
1077 return result;
(gdb)
1078 }
(gdb)
gen_partprune_steps->回到gen_partprune_steps,返回steps链表
(gdb)
gen_partprune_steps (rel=0x20fab08, clauses=0x21c2390, contradictory=0x7ffe1953a8d7) at partprune.c:541
541 return context.steps;
(gdb) p *result
$26 = 0 '\000'
(gdb) p context.steps
$27 = (List *) 0x21c2890
(gdb) p *context.steps
$28 = {type = T_List, length = 3, head = 0x21c2868, tail = 0x21c2e60}
$29 = {type = T_PartitionPruneStepOp}
(gdb) p *(PartitionPruneStepOp *)context.steps->head->data.ptr_value
$30 = {step = {type = T_PartitionPruneStepOp, step_id = 0}, opstrategy = 1, exprs = 0x21c2830, cmpfns = 0x21c27d0,
nullkeys = 0x0}
(gdb) p *(PartitionPruneStepOp *)context.steps->head->next->data.ptr_value
$31 = {step = {type = T_PartitionPruneStepOp, step_id = 1}, opstrategy = 1, exprs = 0x21c2c28, cmpfns = 0x21c2bc8,
nullkeys = 0x0}
(gdb) p *(PartitionPruneStepOp *)context.steps->head->next->next->data.ptr_value
$32 = {step = {type = T_PartitionPruneStepCombine, step_id = 2}, opstrategy = 0, exprs = 0x21c2a10, cmpfns = 0x7e,
nullkeys = 0x10}
(gdb)
gen_partprune_steps->回到prune_append_rel_partitions
(gdb) n
542 }
(gdb)
prune_append_rel_partitions (rel=0x20fab08) at partprune.c:574
574 if (contradictory)
(gdb)
prune_append_rel_partitions->设置上下文环境
(gdb)
578 context.strategy = rel->part_scheme->strategy;
(gdb)
579 context.partnatts = rel->part_scheme->partnatts;
...
prune_append_rel_partitions->调用get_matching_partitions,获取匹配的分区编号(Indexes)
结果为5,即数组下标为0和2的Rel(part_rels数组)
597 partindexes = get_matching_partitions(&context, pruning_steps);
(gdb)
600 i = -1;
(gdb) p partindexes
$33 = (Bitmapset *) 0x21c2ff8
(gdb) p *partindexes
$34 = {nwords = 1, words = 0x21c2ffc}
(gdb) p *partindexes->words
$35 = 5
prune_append_rel_partitions->生成Relids
结果为40,即8+32,即3号和5号Rel
(gdb) n
601 result = NULL;
(gdb)
602 while ((i = bms_next_member(partindexes, i)) >= 0)
(gdb)
603 result = bms_add_member(result, rel->part_rels[i]->relid);
(gdb) p i
$39 = 0
(gdb) n
602 while ((i = bms_next_member(partindexes, i)) >= 0)
(gdb)
603 result = bms_add_member(result, rel->part_rels[i]->relid);
(gdb) p i
$40 = 2
(gdb) n
602 while ((i = bms_next_member(partindexes, i)) >= 0)
(gdb)
605 return result;
(gdb) p result
$41 = (Relids) 0x21c3018
(gdb) p *result
$42 = {nwords = 1, words = 0x21c301c}
(gdb) p result->words[0]
$43 = 40
prune_append_rel_partitions->完成调用
606 }
(gdb)
set_append_rel_size (root=0x2120378, rel=0x20fab08, rti=1, rte=0x20fa3d0) at allpaths.c:922
922 did_pruning = true;
(gdb)
感谢各位的阅读!关于“PostgreSQL在查询分区表时如何确定查询的是哪个分区”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341