返回顶部
首页 > 资讯 > 数据库 >PostgreSQL中query_planner中主计划函数make_one_rel的主实现逻辑是什么
  • 243
分享到

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

2024-04-02 19:04:59 243人浏览 泡泡鱼
摘要

这篇文章主要介绍“postgresql中query_planner中主计划函数make_one_rel的主实现逻辑是什么”,在日常操作中,相信很多人在Postgresql中query_planner中主计划

这篇文章主要介绍“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的主实现逻辑是什么”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

您可能感兴趣的文档:

--结束END--

本文标题: PostgreSQL中query_planner中主计划函数make_one_rel的主实现逻辑是什么

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

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

猜你喜欢
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作