返回顶部
首页 > 资讯 > 数据库 >PostgreSQL在查询分区表时如何确定查询的是哪个分区
  • 943
分享到

PostgreSQL在查询分区表时如何确定查询的是哪个分区

2024-04-02 19:04:59 943人浏览 独家记忆
摘要

这篇文章给大家分享的是有关postgresql在查询分区表时如何确定查询的是哪个分区的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。在规划阶段,函数set_rel_size中,如R

这篇文章给大家分享的是有关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在查询分区表时如何确定查询的是哪个分区”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!

您可能感兴趣的文档:

--结束END--

本文标题: PostgreSQL在查询分区表时如何确定查询的是哪个分区

本文链接: https://lsjlt.com/news/64718.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • PostgreSQL在查询分区表时如何确定查询的是哪个分区
    这篇文章给大家分享的是有关PostgreSQL在查询分区表时如何确定查询的是哪个分区的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。在规划阶段,函数set_rel_size中,如R...
    99+
    2024-04-02
  • 如何在PostgreSQL中实现分区表和分布式查询
    要在PostgreSQL中实现分区表和分布式查询,可以使用以下方法: 使用分区表:PostgreSQL支持表分区,可以根据特定的...
    99+
    2024-03-14
    PostgreSQL
  • mysql如何查询分区表信息
    这篇文章主要讲解了“mysql如何查询分区表信息”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“mysql如何查询分区表信息”吧! ...
    99+
    2024-04-02
  • mysql如何查询表分区信息
    要查询表的分区信息,可以使用以下两种方法: 使用SHOW CREATE TABLE命令查看表的创建语句,其中会包含分区信息。例如:...
    99+
    2024-04-23
    mysql
  • 如何查询ubuntu各分区
    查询ubuntu各分区的方法:使用快捷键Ctrl+Alt+t打开终端。输入以下命令即可查ubuntu各分区,例如:sudo fdisk -l会得到结果如下:Disk /dev/sda: 250.0 GB,&nb...
    99+
    2024-04-02
  • mysql 5.7.11查询分区表的一个问题
    mysql 查询一个分区表,当查询条件存在数据时执行效率OK,当不存在数据时执行不完,一直在sending data,当去掉desc就没问题。换个版本貌似也没问题。 mysql> sele...
    99+
    2024-04-02
  • PostgreSQL 源码解读(98)- 分区表#4(数据查询路由#1-“扩展”分区表)
    在查询分区表的时候PG如何确定查询的是哪个分区?如何确定?相关的机制是什么?接下来几个章节将一一介绍,本节是第一部分。 零、实现机制 我们先看下面的例子,两个普通表t_normal...
    99+
    2024-04-02
  • mysql如何查询区分大小写
    这篇文章主要介绍mysql如何查询区分大小写,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完! 在mysql中,可以利用binary关键字查询区分大小写,该关...
    99+
    2024-04-02
  • mysql查询如何区分大小写
    这篇文章主要介绍mysql查询如何区分大小写,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完! 在mysql中,可以利用select查询语句配合bi...
    99+
    2024-04-02
  • PostgreSQL中分区表查询相关的重要数据结构有哪些
    本篇内容介绍了“PostgreSQL中分区表查询相关的重要数据结构有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能...
    99+
    2024-04-02
  • oracle跨分区查询慢如何优化
    要优化Oracle跨分区查询的性能,可以考虑以下几点: 在查询中尽量避免使用跨分区的条件,尽量只查询单个分区的数据,可以通过分区...
    99+
    2024-05-13
    oracle
  • oracle怎么查询某个分区的数据
    要查询某个分区的数据,可以使用以下步骤: 首先,可以使用以下命令检查数据库中存在的分区表: SELECT DISTINC...
    99+
    2024-04-09
    oracle
  • mongodb查询不区分类型的方法是什么
    在 MongoDB 中,查询不区分类型的方法是使用 `$type` 操作符和 `bsonType` 关键字。`$type` 操作符可...
    99+
    2023-08-31
    mongodb
  • MySQL中存储的数据查询的时候如何区分大小写
    目录场景描述解决办法1. 查询时指定大小写敏感2. 定义表结构时指定字段大小写敏感3. 修改排序规则(COLLATE)COLLATE是用来做什么的?各种COLLATE的区别COLLATE 设置级别及其优先级总结场景描述 ...
    99+
    2023-04-06
    MySQL存储 MySQL数据查询 MySQL区分大小写
  • 如何进行sql表连接查询的分析
    如何进行sql表连接查询的分析,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。连接查询:连接查询是指基于两个或者两个以上的表或者...
    99+
    2024-04-02
  • PHP如何查询特定分类下的商品?
    标题:PHP如何查询特定分类下的商品?详细代码示例分享 在电商网站开发中,需要经常查询特定分类下的商品信息,以便展示给用户。PHP作为一种流行的后端编程语言,能够帮助我们实现这一功能。...
    99+
    2024-03-11
    查询商品分类 php检索分类 分类商品查询
  • Oracle提升查询性能之-简单范围分区表的创建
    分区表的优点: 1.提高查询性能:只需要搜索特定分区,而非整张表,提高了查询速度。 2.节约维护时间:单个分区的数据装载,索引重建,备份,维护远远小于整张表的维护时间。下面就让我们来创建一张分区表 第一步:...
    99+
    2024-04-02
  • MySQL中存储的数据查询的时候区分大小写问题
    场景描述 今天在将 Hive 表同步到 MySQL 之后,其中有一列是唯一列,但是在 MySQL 中查询的时候 count 与 distinct count 查询出来的数值是不一样的,这么来看的话是有...
    99+
    2023-09-02
    mysql 数据库 hive
  • MySQL中存储的数据查询的时候怎么区分大小写
    这篇文章主要介绍了MySQL中存储的数据查询的时候怎么区分大小写的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇MySQL中存储的数据查询的时候怎么区分大小写文章都会有所收获,下面我们一起来看看吧。场景描述今天在...
    99+
    2023-07-05
  • 如何查询云主机绑定的哪个域名
    查看云主机中绑定的域名的方法首先,在计算机中远程连接云主机,进入云主机操作界面;进入到云主机操作界面后,在界面中使用组合键“win+R”运行“inetmgr”,打开iis管理器;iis管理器打开后,在页面左侧菜单栏中点击“网站”选项;点击网...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作