文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

PostgreSQL中query_planner中主计划函数make_one_rel的主实现逻辑是什么

2024-04-02 19:55

关注

这篇文章主要介绍“PostgreSQL中query_planner中主计划函数make_one_rel的主实现逻辑是什么”,在日常操作中,相信很多人在PostgreSQL中query_planner中主计划函数make_one_rel的主实现逻辑是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”PostgreSQL中query_planner中主计划函数make_one_rel的主实现逻辑是什么”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

query_planner代码片段:

     //...

     
     final_rel = make_one_rel(root, joinlist);//执行主要的计划过程
 
     
     if (!final_rel || !final_rel->cheapest_total_path ||
         final_rel->cheapest_total_path->param_info != NULL)
         elog(ERROR, "failed to construct the join relation");//检查
 
     return final_rel;//返回结果

     //...

一、数据结构

RelOptInfo

 typedef struct RelOptInfo
 {
     NodeTag     type;//节点标识
 
     RelOptKind  reloptkind;//RelOpt类型
 
     
     Relids      relids;         
 
     
     double      rows;           
 
     
     bool        consider_startup;   
     bool        consider_param_startup; 
     bool        consider_parallel;  
 
     
     struct PathTarget *reltarget;   
 
     
     List       *pathlist;       
     List       *ppilist;        
     List       *partial_pathlist;   
     struct Path *cheapest_startup_path;//代价最低的启动路径
     struct Path *cheapest_total_path;//代价最低的整体路径
     struct Path *cheapest_unique_path;//代价最低的获取唯一值的路径
     List       *cheapest_parameterized_paths;//代价最低的参数化?路径链表
 
     
     
     Relids      direct_lateral_relids;  
     Relids      lateral_relids; 
 
     
     //reloptkind=RELOPT_BASEREL时使用的数据结构
     Index       relid;          
     Oid         reltablespace;  
     RTEKind     rtekind;        
     AttrNumber  min_attr;       
     AttrNumber  max_attr;       
     Relids     *attr_needed;    
     int32      *attr_widths;    
     List       *lateral_vars;   
     Relids      lateral_referencers;    
     List       *indexlist;      
     List       *statlist;       
     BlockNumber pages;          
     double      tuples;         
     double      allvisfrac;     
     PlannerInfo *subroot;       
     List       *subplan_params; 
     int         rel_parallel_workers;   
 
     
     //FWD相关信息
     Oid         serverid;       
     Oid         userid;         
     bool        useridiscurrent;    
     
     struct FdwRoutine *fdwroutine;
     void       *fdw_private;
 
     
     //已知的,可保证唯一的Relids链表
     List       *unique_for_rels;    
     List       *non_unique_for_rels;    
 
     
     List       *baserestrictinfo;   
     QualCost    baserestrictcost;   
     Index       baserestrict_min_security;  
     List       *joininfo;       
     bool        has_eclass_joins;   
 
     
     bool        consider_partitionwise_join;    
     Relids      top_parent_relids;  
 
     
     //分区表使用
     PartitionScheme part_scheme;    
     int         nparts;         
     struct PartitionBoundInfoData *boundinfo;   
     List       *partition_qual; 
     struct RelOptInfo **part_rels;  
     List      **partexprs;      
     List      **nullable_partexprs; 
     List       *partitioned_child_rels; 
 } RelOptInfo;

二、源码解读

make_one_rel
make_one_rel函数找出执行查询的所有可能访问路径,但不考虑上层的Non-SPJ操作,返回一个最上层的RelOptInfo.
make_one_rel函数分为两个阶段:生成扫描路径(set_base_rel_pathlists)和生成连接路径(make_rel_from_joinlist).
注:SPJ是指选择(Select)/投影(Project)/连接(Join),相对应的Non-SPJ操作是指Group分组/Sort排序等操作

 
 RelOptInfo *
 make_one_rel(PlannerInfo *root, List *joinlist)
 {
     RelOptInfo *rel;
     Index       rti;
 
     
     root->all_baserels = NULL;
     for (rti = 1; rti < root->simple_rel_array_size; rti++)//遍历RelOptInfo
     {
         RelOptInfo *brel = root->simple_rel_array[rti];
 
         
         if (brel == NULL)
             continue;
 
         Assert(brel->relid == rti); 
 
         
         if (brel->reloptkind != RELOPT_BASEREL)
             continue;
 
         root->all_baserels = bms_add_member(root->all_baserels, brel->relid);//添加到all_baserels遍历中
     }
 
     
     //设置RelOptInfo的consider_param_startup变量,是否考量fast-start plans
     set_base_rel_consider_startup(root);
 
     
     set_base_rel_sizes(root);//估算Relation的Size并且设置consider_parallel标记
     set_base_rel_pathlists(root);//生成Relation的扫描(访问)路径
 
     
     rel = make_rel_from_joinlist(root, joinlist);
 
     
     Assert(bms_equal(rel->relids, root->all_baserels));
     //返回最上层的RelOptInfo
     return rel;
 }

//--------------------------------------------------------
 
 static void
 set_base_rel_consider_startup(PlannerInfo *root)
 {
     
     ListCell   *lc;
 
     foreach(lc, root->join_info_list)
     {
         SpecialJoinInfo *sjinfo = (SpecialJoinInfo *) lfirst(lc);
         int         varno;
 
         if ((sjinfo->jointype == JOIN_SEMI || sjinfo->jointype == JOIN_ANTI) &&
             bms_get_singleton_member(sjinfo->syn_righthand, &varno))
         {
             RelOptInfo *rel = find_base_rel(root, varno);
 
             rel->consider_param_startup = true;
         }
     }
 }

//--------------------------------------------------------
 
 static void
 set_base_rel_sizes(PlannerInfo *root)
 {
     Index       rti;
 
     for (rti = 1; rti < root->simple_rel_array_size; rti++)//遍历RelOptInfo数组
     {
         RelOptInfo *rel = root->simple_rel_array[rti];
         RangeTblEntry *rte;
 
         
         if (rel == NULL)
             continue;
 
         Assert(rel->relid == rti);  
 
         
         if (rel->reloptkind != RELOPT_BASEREL)
             continue;
 
         rte = root->simple_rte_array[rti];
 
         
         if (root->glob->parallelModeOK)
             set_rel_consider_parallel(root, rel, rte);
 
         set_rel_size(root, rel, rti, rte);
     }
 }

 
 static void
 set_rel_size(PlannerInfo *root, RelOptInfo *rel,
              Index rti, RangeTblEntry *rte)
 {
     if (rel->reloptkind == RELOPT_BASEREL &&
         relation_excluded_by_constraints(root, rel, rte))
     {
         
         set_dummy_rel_pathlist(rel);//
     }
     else if (rte->inh)//inherit table
     {
         
         set_append_rel_size(root, rel, rti, rte);
     }
     else
     {
         switch (rel->rtekind)
         {
             case RTE_RELATION://数据表
                 if (rte->relkind == RELKIND_FOREIGN_TABLE)//FDW
                 {
                     
                     set_foreign_size(root, rel, rte);
                 }
                 else if (rte->relkind == RELKIND_PARTITIONED_TABLE)//分区表
                 {
                     
                     set_dummy_rel_pathlist(rel);
                 }
                 else if (rte->tablesample != NULL)//采样表
                 {
                     
                     set_tablesample_rel_size(root, rel, rte);
                 }
                 else
                 {
                     
                     set_plain_rel_size(root, rel, rte);//常规的数据表
                 }
                 break;
             case RTE_SUBQUERY://子查询
 
                 
                 set_subquery_pathlist(root, rel, rti, rte);//生成子查询访问路径
                 break;
             case RTE_FUNCTION://FUNCTION
                 set_function_size_estimates(root, rel);
                 break;
             case RTE_TABLEFUNC://TABLEFUNC
                 set_tablefunc_size_estimates(root, rel);
                 break;
             case RTE_VALUES://VALUES
                 set_values_size_estimates(root, rel);
                 break;
             case RTE_CTE://CTE
 
                 
                 if (rte->self_reference)
                     set_worktable_pathlist(root, rel, rte);
                 else
                     set_cte_pathlist(root, rel, rte);
                 break;
             case RTE_NAMEDTUPLESTORE://NAMEDTUPLESTORE,命名元组存储
                 set_namedtuplestore_pathlist(root, rel, rte);
                 break;
             default:
                 elog(ERROR, "unexpected rtekind: %d", (int) rel->rtekind);
                 break;
         }
     }
 
     
     Assert(rel->rows > 0 || IS_DUMMY_REL(rel));
 }
 
//--------------------------------------------------------
 
 static void
 set_base_rel_pathlists(PlannerInfo *root)
 {
     Index       rti;
 
     for (rti = 1; rti < root->simple_rel_array_size; rti++)//遍历RelOptInfo数组
     {
         RelOptInfo *rel = root->simple_rel_array[rti];
 
         
         if (rel == NULL)
             continue;
 
         Assert(rel->relid == rti);  
 
         
         if (rel->reloptkind != RELOPT_BASEREL)
             continue;
 
         set_rel_pathlist(root, rel, rti, root->simple_rte_array[rti]);
     }
 }

 
 static void
 set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
                  Index rti, RangeTblEntry *rte)
 {
     if (IS_DUMMY_REL(rel))
     {
         
     }
     else if (rte->inh)//inherit
     {
         
         set_append_rel_pathlist(root, rel, rti, rte);
     }
     else//常规
     {
         switch (rel->rtekind)
         {
             case RTE_RELATION://数据表
                 if (rte->relkind == RELKIND_FOREIGN_TABLE)//FDW
                 {
                     
                     set_foreign_pathlist(root, rel, rte);
                 }
                 else if (rte->tablesample != NULL)//采样表
                 {
                     
                     set_tablesample_rel_pathlist(root, rel, rte);
                 }
                 else//常规数据表
                 {
                     
                     set_plain_rel_pathlist(root, rel, rte);
                 }
                 break;
             case RTE_SUBQUERY://子查询
                 
                 break;
             case RTE_FUNCTION:
                 
                 set_function_pathlist(root, rel, rte);
                 break;
             case RTE_TABLEFUNC:
                 
                 set_tablefunc_pathlist(root, rel, rte);
                 break;
             case RTE_VALUES:
                 
                 set_values_pathlist(root, rel, rte);
                 break;
             case RTE_CTE:
                 
                 break;
             case RTE_NAMEDTUPLESTORE:
                 
                 break;
             default:
                 elog(ERROR, "unexpected rtekind: %d", (int) rel->rtekind);
                 break;
         }
     }
 
     
     if (rel->reloptkind == RELOPT_BASEREL &&
         bms_membership(root->all_baserels) != BMS_SINGLETON)
         generate_gather_paths(root, rel, false);
 
     
     if (set_rel_pathlist_hook)//钩子函数
         (*set_rel_pathlist_hook) (root, rel, rti, rte);
 
     
     set_cheapest(rel);//找出代价最低的访问路径
 
 #ifdef OPTIMIZER_DEBUG
     debug_print_rel(root, rel);
 #endif
 }

//------------------------------------------------------------
 
 static RelOptInfo *
 make_rel_from_joinlist(PlannerInfo *root, List *joinlist)
 {
     int         levels_needed;
     List       *initial_rels;
     ListCell   *jl;
 
     
     levels_needed = list_length(joinlist);//joinlist链表长度
 
     if (levels_needed <= 0)
         return NULL;            
 
     
     initial_rels = NIL;
     foreach(jl, joinlist)//遍历链表
     {
         Node       *jlnode = (Node *) lfirst(jl);
         RelOptInfo *thisrel;
 
         if (IsA(jlnode, RangeTblRef))//RTR
         {
             int         varno = ((RangeTblRef *) jlnode)->rtindex;
 
             thisrel = find_base_rel(root, varno);
         }
         else if (IsA(jlnode, List))
         {
             
             thisrel = make_rel_from_joinlist(root, (List *) jlnode);//递归调用
         }
         else
         {
             elog(ERROR, "unrecognized joinlist node type: %d",
                  (int) nodeTag(jlnode));
             thisrel = NULL;     
         }
 
         initial_rels = lappend(initial_rels, thisrel);//加入初始化链表中
     }
 
     if (levels_needed == 1)
     {
         
         return (RelOptInfo *) linitial(initial_rels);
     }
     else
     {
         
         root->initial_rels = initial_rels;
 
         if (join_search_hook)//钩子函数
             return (*join_search_hook) (root, levels_needed, initial_rels);
         else if (enable_geqo && levels_needed >= geqo_threshold)
             return geqo(root, levels_needed, initial_rels);//通过遗传算法构建连接访问路径
         else
             return standard_join_search(root, levels_needed, initial_rels);//通过动态规划算法构建连接路径
     }
 }

到此,关于“PostgreSQL中query_planner中主计划函数make_one_rel的主实现逻辑是什么”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-数据库
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯