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

query_planner代码片段:

//.../**Readytodotheprimaryplanning.*/final_rel=make_one_rel(root,joinlist);//执行主要的计划过程/*Checkthatwegotatleastoneusablepath*/if(!final_rel||!final_rel->cheapest_total_path||final_rel->cheapest_total_path->param_info!=NULL)elog(ERROR,"failedtoconstructthejoinrelation");//检查returnfinal_rel;//返回结果//...一、数据结构

RelOptInfo

typedefstructRelOptInfo{NodeTagtype;//节点标识RelOptKindreloptkind;//RelOpt类型/*allrelationsincludedinthisRelOptInfo*/Relidsrelids;/*Relids(rtindex)集合setofbaserelids(rangetableindexes)*//*sizeestimatesgeneratedbyplanner*/doublerows;/*结果元组的估算数量estimatednumberofresulttuples*//*per-relationplannercontrolflags*/boolconsider_startup;/*是否考虑启动成本?是,需要保留启动成本低的路径keepcheap-startup-costpaths?*/boolconsider_param_startup;/*是否考虑参数化?的路径ditto,forparameterizedpaths?*/boolconsider_parallel;/*是否考虑并行处理路径considerparallelpaths?*//*defaultresulttargetlistforPathsscanningthisrelation*/structPathTarget*reltarget;/*扫描该Relation时默认的结果listofVars/Exprs,cost,width*//*materializationinformation*/List*pathlist;/*访问路径链表Pathstructures*/List*ppilist;/*路径链表中使用参数化路径进行ParamPathInfosusedinpathlist*/List*partial_pathlist;/*partialPaths*/structPath*cheapest_startup_path;//代价最低的启动路径structPath*cheapest_total_path;//代价最低的整体路径structPath*cheapest_unique_path;//代价最低的获取唯一值的路径List*cheapest_parameterized_paths;//代价最低的参数化?路径链表/*parameterizationinformationneededforbothbaserelsandjoinrels*//*(seealsolateral_varsandlateral_referencers)*/Relidsdirect_lateral_relids;/*使用lateral语法,需依赖的Relidsrelsdirectlylaterallyreferenced*/Relidslateral_relids;/*minimumparameterizationofrel*//*informationaboutabaserel(notsetforjoinrels!)*///reloptkind=RELOPT_BASEREL时使用的数据结构Indexrelid;/*RelationID*/Oidreltablespace;/*表空间containingtablespace*/RTEKindrtekind;/*基表?子查询?还是函数等等?RELATION,SUBQUERY,FUNCTION,etc*/AttrNumbermin_attr;/*最小的属性编号smallestattrnoofrel(often<0)*/AttrNumbermax_attr;/*最大的属性编号largestattrnoofrel*/Relids*attr_needed;/*数组arrayindexed[min_attr..max_attr]*/int32*attr_widths;/*属性宽度arrayindexed[min_attr..max_attr]*/List*lateral_vars;/*关系依赖的Vars/PHVsLATERALVarsandPHVsreferencedbyrel*/Relidslateral_referencers;/*依赖该关系的Relidsrelsthatreferencemelaterally*/List*indexlist;/*该关系的IndexOptInfo链表listofIndexOptInfo*/List*statlist;/*统计信息链表listofStatisticExtInfo*/BlockNumberpages;/*块数sizeestimatesderivedfrompg_class*/doubletuples;/*元组数*/doubleallvisfrac;/*?*/PlannerInfo*subroot;/*如为子查询,存储子查询的rootifsubquery*/List*subplan_params;/*如为子查询,存储子查询的参数ifsubquery*/intrel_parallel_workers;/*并行执行,需要多少个workers?wantednumberofparallelworkers*//*Informationaboutforeigntablesandforeignjoins*///FWD相关信息Oidserverid;/*identifiesserverforthetableorjoin*/Oiduserid;/*identifiesusertocheckaccessas*/booluseridiscurrent;/*joinisonlyvalidforcurrentuser*//*use"structFdwRoutine"toavoidincludingfdwapi.hhere*/structFdwRoutine*fdwroutine;void*fdw_private;/*cachespaceforrememberingifwehaveproventhisrelationunique*///已知的,可保证唯一的Relids链表List*unique_for_rels;/*knownuniquefortheseotherrelid*set(s)*/List*non_unique_for_rels;/*已知的,不唯一的Relids链表knownnotuniquefortheseset(s)*//*usedbyvariousscansandjoins:*/List*baserestrictinfo;/*如为基本关系,存储约束条件RestrictInfostructures(ifbaserel)*/QualCostbaserestrictcost;/*解析约束表达式的成本?costofevaluatingtheabove*/Indexbaserestrict_min_security;/*最低安全等级minsecurity_levelfoundin*baserestrictinfo*/List*joininfo;/*连接语句的约束条件信息RestrictInfostructuresforjoinclauses*involvingthisrel*/boolhas_eclass_joins;/*是否存在等价类连接?Tmeansjoininfoisincomplete*//*usedbypartitionwisejoins:*/boolconsider_partitionwise_join;/*分区?considerpartitionwise*joinpaths?(if*partitionedrel)*/Relidstop_parent_relids;/*Relidsoftopmostparents(if"other"*rel)*//*usedforpartitionedrelations*///分区表使用PartitionSchemepart_scheme;/*分区的schemaPartitioningscheme.*/intnparts;/*分区数numberofpartitions*/structPartitionBoundInfoData*boundinfo;/*分区边界信息Partitionbounds*/List*partition_qual;/*分区约束partitionconstraint*/structRelOptInfo**part_rels;/*分区的RelOptInfo数组ArrayofRelOptInfosofpartitions,*storedinthesameorderofbounds*/List**partexprs;/*非空分区键表达式Non-nullablepartitionkeyexpressions.*/List**nullable_partexprs;/*可为空的分区键表达式Nullablepartitionkeyexpressions.*/List*partitioned_child_rels;/*RTIndexes链表ListofRTindexes.*/}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排序等操作

/**make_one_rel*Findsallpossibleaccesspathsforexecutingaquery,returninga*singlerelthatrepresentsthejoinofallbaserelsinthequery.*/RelOptInfo*make_one_rel(PlannerInfo*root,List*joinlist){RelOptInfo*rel;Indexrti;/**Constructtheall_baserelsRelidsset.*/root->all_baserels=NULL;for(rti=1;rti<root->simple_rel_array_size;rti++)//遍历RelOptInfo{RelOptInfo*brel=root->simple_rel_array[rti];/*theremaybeemptyslotscorrespondingtonon-baserelRTEs*/if(brel==NULL)continue;Assert(brel->relid==rti);/*sanitycheckonarray*//*ignoreRTEsthatare"otherrels"*/if(brel->reloptkind!=RELOPT_BASEREL)continue;root->all_baserels=bms_add_member(root->all_baserels,brel->relid);//添加到all_baserels遍历中}/*Markbaserelsastowhetherwecareaboutfast-startplans*///设置RelOptInfo的consider_param_startup变量,是否考量fast-startplansset_base_rel_consider_startup(root);/**Computesizeestimatesandconsider_parallelflagsforeachbaserel,*thengenerateaccesspaths.*/set_base_rel_sizes(root);//估算Relation的Size并且设置consider_parallel标记set_base_rel_pathlists(root);//生成Relation的扫描(访问)路径/**Generateaccesspathsfortheentirejointree.*通过动态规划或遗传算法生成连接路径*/rel=make_rel_from_joinlist(root,joinlist);/**Theresultshouldjoinallandonlythequery'sbaserels.*/Assert(bms_equal(rel->relids,root->all_baserels));//返回最上层的RelOptInforeturnrel;}//--------------------------------------------------------/**set_base_rel_consider_startup*Settheconsider_[param_]startupflagsforeachbase-relationentry.**Forthemoment,weonlydealwithconsider_param_startuphere;becausethe*logicforconsider_startupisprettytrivialandisthesameforeverybase*relation,wejustletbuild_simple_rel()initializethatflagcorrectlyto*startwith.Ifthatlogicevergetsmorecomplicateditwouldprobably*bebettertomoveithere.*/staticvoidset_base_rel_consider_startup(PlannerInfo*root){/**Sinceparameterizedpathscanonlybeusedontheinsideofanestloop*joinplan,thereisusuallylittlevalueinconsideringfast-start*plansforthem.However,forrelationsthatareontheRHSofaSEMI*orANTIjoin,afast-startplancanbeusefulbecausewe'reonlygoing*tocareaboutfetchingonetupleanyway.**Tominimizegrowthofplanningtime,wecurrentlyrestrictthisto*caseswheretheRHSisasinglebaserelation,notajoin;thereisno*provisionforconsider_param_startuptogetsetatallonjoinrels.*Alsowedon'tworryaboutappendrels.costsize.c'scostingrulesfor*nestloopsemi/antijoinsdon'tconsidersuchcaseseither.*/ListCell*lc;foreach(lc,root->join_info_list){SpecialJoinInfo*sjinfo=(SpecialJoinInfo*)lfirst(lc);intvarno;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;}}}//--------------------------------------------------------/**set_base_rel_sizes*Setthesizeestimates(rowsandwidths)foreachbase-relationentry.*Alsodeterminewhethertoconsiderparallelpathsforbaserelations.**Wedothisinaseparatepassoverthebaserelssothatrowcount*estimatesareavailableforparameterizedpathgeneration,andalsoso*thateachrel'sconsider_parallelflagissetcorrectlybeforewebeginto*generatepaths.*/staticvoidset_base_rel_sizes(PlannerInfo*root){Indexrti;for(rti=1;rti<root->simple_rel_array_size;rti++)//遍历RelOptInfo数组{RelOptInfo*rel=root->simple_rel_array[rti];RangeTblEntry*rte;/*theremaybeemptyslotscorrespondingtonon-baserelRTEs*/if(rel==NULL)continue;Assert(rel->relid==rti);/*sanitycheckonarray*//*ignoreRTEsthatare"otherrels"*/if(rel->reloptkind!=RELOPT_BASEREL)continue;rte=root->simple_rte_array[rti];/**Ifparallelismisallowableforthisqueryingeneral,seewhether*it'sallowableforthisrelinparticular.Wehavetodothis*beforeset_rel_size(),because(a)ifthisrelisaninheritance*parent,set_append_rel_size()willuseandperhapschangetherel's*consider_parallelflag,and(b)forsomeRTEtypes,set_rel_size()*goesaheadandmakespathsimmediately.*/if(root->glob->parallelModeOK)set_rel_consider_parallel(root,rel,rte);set_rel_size(root,rel,rti,rte);}}/**set_rel_size*Setsizeestimatesforabaserelation*/staticvoidset_rel_size(PlannerInfo*root,RelOptInfo*rel,Indexrti,RangeTblEntry*rte){if(rel->reloptkind==RELOPT_BASEREL&&relation_excluded_by_constraints(root,rel,rte)){/**Weprovedwedon'tneedtoscantherelviaconstraintexclusion,*sosetupasingledummypathforit.Hereweonlycheckthisfor*regularbaserels;ifit'sanotherrel,CEwasalreadycheckedin*set_append_rel_size().**Inthiscase,wegoaheadandsetuptherelation'spathrightaway*insteadofleavingitforset_rel_pathlisttodo.Thisisbecause*wedon'thaveaconventionformarkingarelasdummyexceptby*assigningadummypathtoit.*/set_dummy_rel_pathlist(rel);//}elseif(rte->inh)//inherittable{/*It'san"appendrelation",processaccordingly*/set_append_rel_size(root,rel,rti,rte);}else{switch(rel->rtekind){caseRTE_RELATION://数据表if(rte->relkind==RELKIND_FOREIGN_TABLE)//FDW{/*Foreigntable*/set_foreign_size(root,rel,rte);}elseif(rte->relkind==RELKIND_PARTITIONED_TABLE)//分区表{/**Apartitionedtablewithoutanypartitionsismarkedas*adummyrel.*/set_dummy_rel_pathlist(rel);}elseif(rte->tablesample!=NULL)//采样表{/*Sampledrelation*/set_tablesample_rel_size(root,rel,rte);}else{/*Plainrelation*/set_plain_rel_size(root,rel,rte);//常规的数据表}break;caseRTE_SUBQUERY://子查询/**Subqueriesdon'tsupportmakingachoicebetween*parameterizedandunparameterizedpaths,sojustgoahead*andbuildtheirpathsimmediately.*/set_subquery_pathlist(root,rel,rti,rte);//生成子查询访问路径break;caseRTE_FUNCTION://FUNCTIONset_function_size_estimates(root,rel);break;caseRTE_TABLEFUNC://TABLEFUNCset_tablefunc_size_estimates(root,rel);break;caseRTE_VALUES://VALUESset_values_size_estimates(root,rel);break;caseRTE_CTE://CTE/**CTEsdon'tsupportmakingachoicebetweenparameterized*andunparameterizedpaths,sojustgoaheadandbuildtheir*pathsimmediately.*/if(rte->self_reference)set_worktable_pathlist(root,rel,rte);elseset_cte_pathlist(root,rel,rte);break;caseRTE_NAMEDTUPLESTORE://NAMEDTUPLESTORE,命名元组存储set_namedtuplestore_pathlist(root,rel,rte);break;default:elog(ERROR,"unexpectedrtekind:%d",(int)rel->rtekind);break;}}/**Weinsistthatallnon-dummyrelshaveanonzerorowcountestimate.*/Assert(rel->rows>0||IS_DUMMY_REL(rel));}//--------------------------------------------------------/**set_base_rel_pathlists*Findsallpathsavailableforscanningeachbase-relationentry.*Sequentialscanandanyavailableindicesareconsidered.*Eachusefulpathisattachedtoitsrelation's'pathlist'field.**为每一个baserels找出所有可用的访问路径(顺序扫描和所有可用的索引都会考虑在内)*每一个可用的路径都会添加到pathlist链表中**/staticvoidset_base_rel_pathlists(PlannerInfo*root){Indexrti;for(rti=1;rti<root->simple_rel_array_size;rti++)//遍历RelOptInfo数组{RelOptInfo*rel=root->simple_rel_array[rti];/*theremaybeemptyslotscorrespondingtonon-baserelRTEs*/if(rel==NULL)continue;Assert(rel->relid==rti);/*sanitycheckonarray*//*ignoreRTEsthatare"otherrels"*/if(rel->reloptkind!=RELOPT_BASEREL)continue;set_rel_pathlist(root,rel,rti,root->simple_rte_array[rti]);}}/**set_rel_pathlist*Buildaccesspathsforabaserelation*/staticvoidset_rel_pathlist(PlannerInfo*root,RelOptInfo*rel,Indexrti,RangeTblEntry*rte){if(IS_DUMMY_REL(rel)){/*Wealreadyprovedtherelationempty,sonothingmoretodo*/}elseif(rte->inh)//inherit{/*It'san"appendrelation",processaccordingly*/set_append_rel_pathlist(root,rel,rti,rte);}else//常规{switch(rel->rtekind){caseRTE_RELATION://数据表if(rte->relkind==RELKIND_FOREIGN_TABLE)//FDW{/*Foreigntable*/set_foreign_pathlist(root,rel,rte);}elseif(rte->tablesample!=NULL)//采样表{/*Sampledrelation*/set_tablesample_rel_pathlist(root,rel,rte);}else//常规数据表{/*Plainrelation*/set_plain_rel_pathlist(root,rel,rte);}break;caseRTE_SUBQUERY://子查询/*Subquery---已在set_rel_size处理,fullyhandledduringset_rel_size*/break;caseRTE_FUNCTION:/*RangeFunction*/set_function_pathlist(root,rel,rte);break;caseRTE_TABLEFUNC:/*TableFunction*/set_tablefunc_pathlist(root,rel,rte);break;caseRTE_VALUES:/*Valueslist*/set_values_pathlist(root,rel,rte);break;caseRTE_CTE:/*CTEreference---fullyhandledduringset_rel_size*/break;caseRTE_NAMEDTUPLESTORE:/*tuplestorereference---fullyhandledduringset_rel_size*/break;default:elog(ERROR,"unexpectedrtekind:%d",(int)rel->rtekind);break;}}/**Ifthisisabaserel,weshouldnormallyconsidergatheringanypartial*pathswemayhavecreatedforit.**However,ifthisisaninheritancechild,skipit.Otherwise,wecould*endupwithaverylargenumberofgathernodes,eachtryingtograb*itsownpoolofworkers.Instead,we'llconsidergatheringpartial*pathsfortheparentappendrel.**Also,ifthisisthetopmostscan/joinrel(thatis,theonlybaserel),*wepostponethisuntilthefinalscan/jointargelistisavailable(see*grouping_planner).*/if(rel->reloptkind==RELOPT_BASEREL&&bms_membership(root->all_baserels)!=BMS_SINGLETON)generate_gather_paths(root,rel,false);/**AllowaplugintoeditorializeonthesetofPathsforthisbase*relation.Itcouldaddnewpaths(suchasCustomPaths)bycalling*add_path(),ordeleteormodifypathsaddedbythecorecode.*/if(set_rel_pathlist_hook)//钩子函数(*set_rel_pathlist_hook)(root,rel,rti,rte);/*Nowfindthecheapestofthepathsforthisrel*/set_cheapest(rel);//找出代价最低的访问路径#ifdefOPTIMIZER_DEBUGdebug_print_rel(root,rel);#endif}//------------------------------------------------------------/**make_rel_from_joinlist*Buildaccesspathsusinga"joinlist"toguidethejoinpathsearch.**根据joinlist构建连接访问路径,joinlist是函数deconstruct_jointree函数的返回**Seecommentsfordeconstruct_jointree()fordefinitionofthejoinlist*datastructure.*/staticRelOptInfo*make_rel_from_joinlist(PlannerInfo*root,List*joinlist){intlevels_needed;List*initial_rels;ListCell*jl;/**Countthenumberofchildjoinlistnodes.Thisisthedepthofthe*dynamic-programmingalgorithmwemustemploytoconsiderallwaysof*joiningthechildnodes.*/levels_needed=list_length(joinlist);//joinlist链表长度if(levels_needed<=0)returnNULL;/*nothingtodo?*//**Constructalistofrelscorrespondingtothechildjoinlistnodes.*Thismaycontainbothbaserelsandrelsconstructedaccordingto*sub-joinlists.*/initial_rels=NIL;foreach(jl,joinlist)//遍历链表{Node*jlnode=(Node*)lfirst(jl);RelOptInfo*thisrel;if(IsA(jlnode,RangeTblRef))//RTR{intvarno=((RangeTblRef*)jlnode)->rtindex;thisrel=find_base_rel(root,varno);}elseif(IsA(jlnode,List)){/*Recursetohandlesubproblem*/thisrel=make_rel_from_joinlist(root,(List*)jlnode);//递归调用}else{elog(ERROR,"unrecognizedjoinlistnodetype:%d",(int)nodeTag(jlnode));thisrel=NULL;/*keepcompilerquiet*/}initial_rels=lappend(initial_rels,thisrel);//加入初始化链表中}if(levels_needed==1){/**Singlejoinlistnode,sowe'redone.*/return(RelOptInfo*)linitial(initial_rels);}else{/**Considerthedifferentordersinwhichwecouldjointherels,*usingaplugin,GEQO,ortheregularjoinsearchcode.**Weputtheinitial_relslistintoaPlannerInfofieldbecause*has_legal_joinclause()needstolookatit(ugly:-().*/root->initial_rels=initial_rels;if(join_search_hook)//钩子函数return(*join_search_hook)(root,levels_needed,initial_rels);elseif(enable_geqo&&levels_needed>=geqo_threshold)returngeqo(root,levels_needed,initial_rels);//通过遗传算法构建连接访问路径elsereturnstandard_join_search(root,levels_needed,initial_rels);//通过动态规划算法构建连接路径}}

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