PostgreSQL中grouping_planner函数有什么作用
这篇文章主要介绍“PostgreSQL中grouping_planner函数有什么作用”,在日常操作中,相信很多人在PostgreSQL中grouping_planner函数有什么作用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”PostgreSQL中grouping_planner函数有什么作用”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!
源码解读分组/聚集等操作是在一个Relation上叠加分组/聚集运算,grouping_planner函数首先通过query_planner函数生成一个新的关系,然后在此关系上attached分组/聚集等操作。
/*--------------------*grouping_planner*Performplanningstepsrelatedtogrouping,aggregation,etc.*执行与与分组/聚集相关的"规划步骤".*分组/聚集等操作是在一个Relation上叠加分组/聚集运算,*PG首先通过query_planner函数生成一个新的关系,然后在此关系上attached分组/聚集等操作**Thisfunctionaddsallrequiredtop-levelprocessingtothescan/join*Path(s)producedbyquery_planner.**该函数还处理了所有需要在顶层处理的扫描/连接路径(通过query_planner函数生成)**Ifinheritance_updateistrue,we'rebeingcalledfrominheritance_planner*andshouldnotincludeaModifyTablestepintheresultingPath(s).*(inheritance_plannerwillcreateasingleModifyTablenodecoveringallthe*targettables.)**如果标志inheritance_update为true,这个函数的调用者是inheritance_planner,在结果路径中*不应包含ModifyTable步骤(inheritance_planner会创建一个单独的覆盖所有目标表的ModifyTable节点).**tuple_fractionisthefractionoftuplesweexpectwillberetrieved.*tuple_fractionisinterpretedasfollows:*0:expectalltuplestoberetrieved(normalcase)*0<tuple_fraction<1:expectthegivenfractionoftuplesavailable*fromtheplantoberetrieved*tuple_fraction>=1:tuple_fractionistheabsolutenumberoftuples*expectedtoberetrieved(ie,aLIMITspecification)**tuple_fraction是我们希望搜索的元组比例:*0:正常情况下,期望扫描所有的元组*大于0小于1:按给定的比例扫描*大于等于1:扫描的元组数量(比如通过LIMIT语句指定)**Returnsnothing;theusefuloutputisinthePathsweattachtothe*(UPPERREL_FINAL,NULL)upperrelin*root.Inaddition,*root->processed_tlistcontainsthefinalprocessedtargetlist.**该函数没有返回值,有用的输出是root->upperrel->Paths,另外,root->processed_tlist中存储最终的投影列**Notethatwehavenotdoneset_cheapest()onthefinalrel;it'sconvenient*toleavethistothecaller.*--------------------*/staticvoidgrouping_planner(PlannerInfo*root,boolinheritance_update,doubletuple_fraction){Query*parse=root->parse;List*tlist;int64offset_est=0;int64count_est=0;doublelimit_tuples=-1.0;boolhave_postponed_srfs=false;PathTarget*final_target;List*final_targets;List*final_targets_contain_srfs;boolfinal_target_parallel_safe;RelOptInfo*current_rel;RelOptInfo*final_rel;ListCell*lc;/*Tweakcaller-suppliedtuple_fractionifhaveLIMIT/OFFSET*///如果存在LIMIT/OFFSET子句,调整tuple_fractionif(parse->limitCount||parse->limitOffset)//存在LIMIT/OFFSET语句{tuple_fraction=preprocess_limit(root,tuple_fraction,&offset_est,&count_est);//获取元组数量/**IfwehaveaknownLIMIT,anddon'thaveanunknownOFFSET,wecan*estimatetheeffectsofusingaboundedsort.*如果我们有一个已知LIMIT,并且没有未知的OFFSET,我们可以估算使用有界排序的效果。*/if(count_est>0&&offset_est>=0)limit_tuples=(double)count_est+(double)offset_est;//}/*Maketuple_fractionaccessibletolower-levelroutines*///使tuple_fraction可被低级别的处理过程访问(在优化器信息中设置)root->tuple_fraction=tuple_fraction;//设置值if(parse->setOperations)//集合操作,如UNION等{/**Ifthere'satop-levelORDERBY,assumewehavetofetchallthe*tuples.Thismightbetoosimplisticgivenallthehackerybelow*topossiblyavoidthesort;buttheoddsofaccurateestimateshere*areprettylowanyway.XXXtrytogetridofthisinfavorof*lettingplan_set_operationsgeneratebothfast-startand*cheapest-totalpaths.*如果语句的最外层(顶级)存在ORDERBY子句,假设我们必须获取所有元组。*这可能过于简单,但无论如何,准确估计的几率是相当低的。*XXX试图摆脱这种情况,让plan_set_operations同时生成快速启动和最便宜的路径。*/if(parse->sortClause)root->tuple_fraction=0.0;//存在排序操作,需扫描所有的元组/**ConstructPathsforsetoperations.Theresultswillnotneedany*workexceptperhapsatop-levelsortand/orLIMIT.Notethatany*specialworkforrecursiveunionsistheresponsibilityof*plan_set_operations.*为集合操作构造路径。*除了最外层的SORT/LIMIT操作外不需要作其他操作。注意,递归联合的任何特殊工作都是plan_set_operations负责。*/current_rel=plan_set_operations(root);//调用集合操作的"规划"函数/**Weshouldnotneedtocallpreprocess_targetlist,sincewemustbe*inaSELECTquerynode.Instead,usethetargetlistreturnedby*plan_set_operations(sincethistellswhetheritreturnedany*resjunkcolumns!),andtransferanysortkeyinformationfromthe*originaltlist.*我们不需要调用preprocess_targetlist函数,因为执行这些操作必须在SELECT查询NODE中。*相反,使用plan_set_operations函数返回的targetlist(因为这告诉它是否返回了所有的resjunk列),*并从原始投影列链表tlist中传输所有的排序sort键信息。*/Assert(parse->commandType==CMD_SELECT);tlist=root->processed_tlist;/*从plan_set_operations函数的返回结果中获取;fromplan_set_operations*//*forsafety,copyprocessed_tlistinsteadofmodifyingin-place*///为了安全起见,复制processed_tlist,而不是就地修改tlist=postprocess_setop_tlist(copyObject(tlist),parse->targetList);/*Saveasidethefinaldecoratedtlist*///root->processed_tlist=tlist;/*AlsoextractthePathTargetformofthesetopresulttlist*///从集合操作结果投影列中获取PathTarget格式的结果列final_target=current_rel->cheapest_total_path->pathtarget;/*Andcheckwhetherit'sparallelsafe*///检查是否并行安全final_target_parallel_safe=is_parallel_safe(root,(Node*)final_target->exprs);/*Thesetopresulttlistcouldn'tcontainanySRFs*///集合操作结果投影列不能包含任何的SRFsAssert(!parse->hasTargetSRFs);final_targets=final_targets_contain_srfs=NIL;/**Can'thandleFOR[KEY]UPDATE/SHAREhere(parsershouldhave*checkedalready,butlet'smakesure).*无法在这里处理[KEY]更新/共享(解析器应该已经检查过了,但需要确认)。*/if(parse->rowMarks)ereport(ERROR,(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),/*------translator:%sisaSQLrowlockingclausesuchasFORUPDATE*/errmsg("%sisnotallowedwithUNION/INTERSECT/EXCEPT",LCS_asString(linitial_node(RowMarkClause,parse->rowMarks)->strength))));/**Calculatepathkeysthatrepresentresultorderingrequirements*计算表示结果排序需求的pathkeys*/Assert(parse->distinctClause==NIL);root->sort_pathkeys=make_pathkeys_for_sortclauses(root,parse->sortClause,tlist);}else//非集合操作{/*Nosetoperations,doregularplanning*///没有集合操作,执行常规的规划过程PathTarget*sort_input_target;List*sort_input_targets;List*sort_input_targets_contain_srfs;boolsort_input_target_parallel_safe;PathTarget*grouping_target;List*grouping_targets;List*grouping_targets_contain_srfs;boolgrouping_target_parallel_safe;PathTarget*scanjoin_target;List*scanjoin_targets;List*scanjoin_targets_contain_srfs;boolscanjoin_target_parallel_safe;boolscanjoin_target_same_exprs;boolhave_grouping;AggClauseCostsagg_costs;WindowFuncLists*wflists=NULL;List*activeWindows=NIL;grouping_sets_data*gset_data=NULL;standard_qp_extraqp_extra;/*ArecursivequeryshouldalwayshavesetOperations*///递归查询应包含集合操作,检查!Assert(!root->hasRecursion);//检查/*PreprocessgroupingsetsandGROUPBYclause,ifany*///预处理groupingsets语句和GROUPBY子句if(parse->groupingSets)//{gset_data=preprocess_grouping_sets(root);//预处理groupingsets语句}else{/*PreprocessregularGROUPBYclause,ifany*///如处理常规的GROUPBY子句if(parse->groupClause)parse->groupClause=preprocess_groupclause(root,NIL);//处理普通的GroupBy语句}/*Preprocesstargetlist*///预处理投影列tlist=preprocess_targetlist(root);//处理投影列/**Wearenowdonehackingupthequery'stargetlist.Mostofthe*remainingplanningworkwillbedonewiththePathTarget*representationoftlists,butsaveasidethefullrepresentationso*thatwecantransferitsdecoration(resnamesetc)tothetopmost*tlistofthefinishedPlan.*现在已经完成了对查询语句targetlist的hacking工作。*剩下的大部分规划工作将使用tlists的PathTarget来完成,*但是需要保留完整的信息,这样我们就可以将它的修饰信息(如resname等)转移到完成计划的最顶层tlist中。*/root->processed_tlist=tlist;//赋值/**Collectstatisticsaboutaggregatesforestimatingcosts,andmark*alltheaggregateswithresolvedaggtranstypes.Wemustdothis*beforeslicinganddicingthetlistintovariouspathtargets,else*somecopiesoftheAggrefnodesmightescapebeingmarkedwiththe*correcttranstypes.*收集关于聚集操作的统计数据以估计成本,并在所有聚集操作上标上已解决的aggtranstypes。*必须在将tlist切割成各种PathKeys之前完成这项工作,*否则一些Aggref节点的副本中正确transtypes可能会被替换。**Note:currently,wedonotdetectduplicateaggregateshere.This*mayresultinsomewhat-overestimatedcost,whichisfineforour*purposessinceallPathswillgetchargedthesame.Butatsome*pointwemightwishtodothatdetectionintheplanner,rather*thanduringexecutorstartup.*注意:目前,我们没有检测到重复的聚合。*这可能会导致一些过高估算的成本,这对于我们的目的来说是好的,因为所有的Path都会耗费相同的成本。*但在某些时候,可能希望在计划器中进行检测,而不是在执行器executor启动期间。*/MemSet(&agg_costs,0,sizeof(AggClauseCosts));if(parse->hasAggs)//存在聚合函数{get_agg_clause_costs(root,(Node*)tlist,AGGSPLIT_SIMPLE,&agg_costs);//收集用于估算成本的统计信息get_agg_clause_costs(root,parse->havingQual,AGGSPLIT_SIMPLE,&agg_costs);//收集用于估算成本的统计信息}/**Locateanywindowfunctionsinthetlist.(Wedon'tneedtolook*anywhereelse,sinceexpressionsusedinORDERBYwillbeinthere*too.)Notethattheycouldallhavebeeneliminatedbyconstant*folding,inwhichcasewedon'tneedtodoanymorework.*在tlist中找到所有的窗口函数。*(我们不需要在其他地方查找,因为ORDERBY中使用的表达式也在那里。)*注意,它们可以通过不断折叠来消除,在这种情况下,我们不需要做更多的工作。*/if(parse->hasWindowFuncs)//窗口函数{wflists=find_window_functions((Node*)tlist,list_length(parse->windowClause));if(wflists->numWindowFuncs>0)activeWindows=select_active_windows(root,wflists);elseparse->hasWindowFuncs=false;}/**PreprocessMIN/MAXaggregates,ifany.Note:becarefulabout*addinglogicbetweenhereandthequery_planner()call.Anything*thatisneededinMIN/MAX-optimizablecaseswillhavetobe*duplicatedinplanagg.c.*重新处理MAX/MIN聚集操作,如果有的话。*注意:在这里和query_planner()调用之间添加逻辑时要小心。*在MIN/MAX优化情况下需要的所有东西都必须在plan.c中重复。*/if(parse->hasAggs)//预处理最大最小聚合preprocess_minmax_aggregates(root,tlist);/**Figureoutwhetherthere'sahardlimitonthenumberofrowsthat*query_planner'sresultsubplanneedstoreturn.Evenifweknowa*hardlimitoverall,itdoesn'tapplyifthequeryhasany*grouping/aggregationoperations,orSRFsinthetlist.*计算query_planner结果子计划需要返回的行数是否有硬性限制。*即使我们知道总的强制限制,如果查询在tlist中有任何分组/聚合操作或SRFs,它也不适用。*/if(parse->groupClause||parse->groupingSets||parse->distinctClause||parse->hasAggs||parse->hasWindowFuncs||parse->hasTargetSRFs||root->hasHavingQual)//存在GroupBy/GroupingSet等语句,则limit_tuples设置为-1root->limit_tuples=-1.0;elseroot->limit_tuples=limit_tuples;//否则,正常赋值/*Setupdataneededbystandard_qp_callback*///配置standard_qp_callback函数需要的相关数据qp_extra.tlist=tlist;//赋值qp_extra.activeWindows=activeWindows;qp_extra.groupClause=(gset_data?(gset_data->rollups?linitial_node(RollupData,gset_data->rollups)->groupClause:NIL):parse->groupClause);/**Generatethebestunsortedandpresortedpathsforthescan/join*portionofthisQuery,ietheprocessingrepresentedbythe*FROM/WHEREclauses.(Notetheremaynotbeanypresortedpaths.)*Wealsogenerate(instandard_qp_callback)pathkeyrepresentations*ofthequery'ssortclause,distinctclause,etc.*为这个查询的扫描/连接部分(即FROM/WHERE子句表示的处理)生成最好的未排序和预排序路径。*(注意,可能没有任何预先设置的路径。)*我们还生成(在standard_qp_callback中)查询语句的sort子句和distinct子句对应的PathKey。*///为查询中的扫描/连接部分生成最优的未排序/预排序路径(如FROM/WHERE语句表示的处理过程)current_rel=query_planner(root,tlist,standard_qp_callback,&qp_extra);/**Convertthequery'sresulttlistintoPathTargetformat.*转换查询结果为PathTarget格式**Note:it'sdesirabletonotdothistillafterquery_planner(),*becausethetargetwidthestimatescanuseper-Varwidthnumbers*thatwereobtainedwithinquery_planner().*注意:在query_planner()之后才需要这样做,因为目标列的宽度估算可以使用在query_planner()中获得的每个VAR信息。*/final_target=create_pathtarget(root,tlist);final_target_parallel_safe=is_parallel_safe(root,(Node*)final_target->exprs);/**IfORDERBYwasgiven,considerwhetherweshoulduseapost-sort*projection,andcomputetheadjustedtargetforprecedingstepsif*so.*如果存在ORDERBY子句,考虑是否使用post-sort投影,如使用则计算前面已调整过的步骤目标列。*/if(parse->sortClause)//存在sort语句?{sort_input_target=make_sort_input_target(root,final_target,&have_postponed_srfs);sort_input_target_parallel_safe=is_parallel_safe(root,(Node*)sort_input_target->exprs);}else{sort_input_target=final_target;//不存在,则直接赋值sort_input_target_parallel_safe=final_target_parallel_safe;}/**Ifwehavewindowfunctionstodealwith,theoutputfromany*groupingstepneedstobewhatthewindowfunctionswant;*otherwise,itshouldbesort_input_target.*如果要处理窗口函数,任何分组步骤的输出都需要满足窗口函数的要求;*否则,它应该是sort_input_target。*/if(activeWindows)//存在窗口函数?{grouping_target=make_window_input_target(root,final_target,activeWindows);grouping_target_parallel_safe=is_parallel_safe(root,(Node*)grouping_target->exprs);}else{grouping_target=sort_input_target;grouping_target_parallel_safe=sort_input_target_parallel_safe;}/**Ifwehavegroupingoraggregationtodo,thetopmostscan/join*plannodemustemitwhatthegroupingstepwants;otherwise,it*shouldemitgrouping_target.*如果要进行分组或聚合,最外层的扫描/连接计划节点必须发出分组步骤需要的内容;*否则,它应该设置grouping_target。*/have_grouping=(parse->groupClause||parse->groupingSets||parse->hasAggs||root->hasHavingQual);if(have_grouping){//存在group等分组语句scanjoin_target=make_group_input_target(root,final_target);scanjoin_target_parallel_safe=is_parallel_safe(root,(Node*)grouping_target->exprs);}else{scanjoin_target=grouping_target;scanjoin_target_parallel_safe=grouping_target_parallel_safe;}/**IfthereareanySRFsinthetargetlist,wemustseparateeachof*thesePathTargetsintoSRF-computingandSRF-freetargets.Replace*eachofthenamedtargetswithaSRF-freeversion,andrememberthe*listofadditionalprojectionstepsweneedtoaddafterwards.*如果targetlist中有任何SRFs,我们必须将这些PathKeys分别划分为SRF-computing和SRF-free目标列。*用一个没有SRF的版本替换每个指定的目标,并记住后面需要添加的其他投影步骤链表。*/if(parse->hasTargetSRFs)//存在SRFs{/*final_targetdoesn'trecomputeanySRFsinsort_input_target*///在sort_input_target中不需要重复计算SRFssplit_pathtarget_at_srfs(root,final_target,sort_input_target,&final_targets,&final_targets_contain_srfs);final_target=linitial_node(PathTarget,final_targets);Assert(!linitial_int(final_targets_contain_srfs));/*likewiseforsort_input_targetvs.grouping_target*/split_pathtarget_at_srfs(root,sort_input_target,grouping_target,&sort_input_targets,&sort_input_targets_contain_srfs);sort_input_target=linitial_node(PathTarget,sort_input_targets);Assert(!linitial_int(sort_input_targets_contain_srfs));/*likewiseforgrouping_targetvs.scanjoin_target*/split_pathtarget_at_srfs(root,grouping_target,scanjoin_target,&grouping_targets,&grouping_targets_contain_srfs);grouping_target=linitial_node(PathTarget,grouping_targets);Assert(!linitial_int(grouping_targets_contain_srfs));/*scanjoin_targetwillnothaveanySRFsprecomputedforit*/split_pathtarget_at_srfs(root,scanjoin_target,NULL,&scanjoin_targets,&scanjoin_targets_contain_srfs);scanjoin_target=linitial_node(PathTarget,scanjoin_targets);Assert(!linitial_int(scanjoin_targets_contain_srfs));}else{/*initializelists;formostofthese,dummyvaluesareOK*///初始化链表final_targets=final_targets_contain_srfs=NIL;sort_input_targets=sort_input_targets_contain_srfs=NIL;grouping_targets=grouping_targets_contain_srfs=NIL;scanjoin_targets=list_make1(scanjoin_target);scanjoin_targets_contain_srfs=NIL;}/*Applyscan/jointarget.*///应用扫描/连接targetscanjoin_target_same_exprs=list_length(scanjoin_targets)==1&&equal(scanjoin_target->exprs,current_rel->reltarget->exprs);apply_scanjoin_target_to_paths(root,current_rel,scanjoin_targets,scanjoin_targets_contain_srfs,scanjoin_target_parallel_safe,scanjoin_target_same_exprs);/**Savethevariousupper-relPathTargetswejustcomputedinto*root->upper_targets[].Thecorecodedoesn'tusethis,butit*providesaconvenientplaceforextensionstogetattheinfo.For*consistency,wesavealltheintermediatetargets,eventhoughsome*ofthecorrespondingupperrelsmightnotbeneededforthisquery.*保存刚刚计算的各种upper->upper_targets[]信息。*核心代码不使用这个功能,但是它为扩展提供了一个方便的地方来获取信息。*为了保持一致性,我们保存了所有的中间目标列,即使这个查询可能不需要一些相应的上层关系。*///赋值root->upper_targets[UPPERREL_FINAL]=final_target;root->upper_targets[UPPERREL_WINDOW]=sort_input_target;root->upper_targets[UPPERREL_GROUP_AGG]=grouping_target;/**Ifwehavegroupingand/oraggregation,considerwaystoimplement*that.Webuildanewupperrelrepresentingtheoutputofthis*phase.*如果我们有分组和/或聚合,考虑如何实现它。需要构建一个表示此阶段输出的上层关系。*/if(have_grouping)//存在分组操作{current_rel=create_grouping_paths(root,current_rel,grouping_target,grouping_target_parallel_safe,&agg_costs,gset_data);//创建分组访问路径/*Fixthingsupifgrouping_targetcontainsSRFs*/if(parse->hasTargetSRFs)adjust_paths_for_srfs(root,current_rel,grouping_targets,grouping_targets_contain_srfs);}/**Ifwehavewindowfunctions,considerwaystoimplementthose.We*buildanewupperrelrepresentingtheoutputofthisphase.*如果有窗口函数,考虑如何实现这些函数。*我们建立一个新的上层关系表示这个阶段的输出。*/if(activeWindows)//存在窗口函数{current_rel=create_window_paths(root,current_rel,grouping_target,sort_input_target,sort_input_target_parallel_safe,tlist,wflists,activeWindows);/*Fixthingsupifsort_input_targetcontainsSRFs*/if(parse->hasTargetSRFs)adjust_paths_for_srfs(root,current_rel,sort_input_targets,sort_input_targets_contain_srfs);}/**IfthereisaDISTINCTclause,considerwaystoimplementthat.We*buildanewupperrelrepresentingtheoutputofthisphase.*如果有一个DISTINCT子句,考虑如何实现它。构建一个表示此阶段输出的上层关系。*/if(parse->distinctClause)//存在distinct?{current_rel=create_distinct_paths(root,current_rel);}}/*endofif(setOperations)*//**IfORDERBYwasgiven,considerwaystoimplementthat,andgeneratea*newupperrelcontainingonlypathsthatemitthecorrectorderingand*projectthecorrectfinal_target.Wecanapplytheoriginal*limit_tupleslimitinsortcostinghere,butonlyifthereareno*postponedSRFs.*如果指定了ORDERBY,考虑实现它的方法,并生成一个仅包含ORDER和final_target的Path的上层关系。*我们可以在排序成本中应用初始的limit_tuples限制,但前提是没有延迟的SRFs。*/if(parse->sortClause)//存在sort语句?{current_rel=create_ordered_paths(root,current_rel,final_target,final_target_parallel_safe,have_postponed_srfs?-1.0:limit_tuples);/*Fixthingsupiffinal_targetcontainsSRFs*/if(parse->hasTargetSRFs)adjust_paths_for_srfs(root,current_rel,final_targets,final_targets_contain_srfs);}/**Nowwearepreparedtobuildthefinal-outputupperrel.*可以构建最终的关系了!*/final_rel=fetch_upper_rel(root,UPPERREL_FINAL,NULL);//获取最终的RelOptInfo(用于替换RTE)/**Iftheinputrelismarkedconsider_parallelandthere'snothingthat's*notparallel-safeintheLIMITclause,thenthefinal_relcanbemarked*consider_parallelaswell.NotethatifthequeryhasrowMarksoris*notaSELECT,consider_parallelwillbefalseforeveryrelationinthe*query.*如果关系被标记为consider_parallel,并且在LIMIT子句中没有任何非并行安全的地方,*那么final_rel也可以被标记为consider_parallel。*请注意,如果查询有rowMarks或不是SELECT语句,则认为对查询中的每个关系consider_parallel都为false。*/if(current_rel->consider_parallel&&is_parallel_safe(root,parse->limitOffset)&&is_parallel_safe(root,parse->limitCount))final_rel->consider_parallel=true;//并行/**Ifthecurrent_relbelongstoasingleFDW,sodoesthefinal_rel.*如current_rel属于某个单独的FDW,设置final_rel信息*/final_rel->serverid=current_rel->serverid;final_rel->userid=current_rel->userid;final_rel->useridiscurrent=current_rel->useridiscurrent;final_rel->fdwroutine=current_rel->fdwroutine;/**Generatepathsforthefinal_rel.Insertallsurvivingpaths,with*LockRows,Limit,and/orModifyTablestepsaddedifneeded.*为final_rel生成访问路径.*插入所有筛选后的访问路径,包含需添加的LockRows/Limit/ModifyTable步骤*/foreach(lc,current_rel->pathlist)//逐一遍历访问路径{Path*path=(Path*)lfirst(lc);/**IfthereisaFOR[KEY]UPDATE/SHAREclause,addtheLockRowsnode.*(Note:weintentionallytestparse->rowMarksnotroot->rowMarks*here.Ifthereareonlynon-lockingrowmarks,theyshouldbe*handledbytheModifyTablenodeinstead.However,root->rowMarks*iswhatgoesintotheLockRowsnode.)*如果存在FOR[KEY]UPDATE/SHARE子句,则添加LockRows节点。*(注意:我们在这里有意测试的是parse->rowMarks,而不是root->rowMarks。*如果只有非锁定行标记,则应该由ModifyTable节点处理。*但是,root->rowMarks是进入LockRows节点的行标记。*/if(parse->rowMarks){path=(Path*)create_lockrows_path(root,final_rel,path,root->rowMarks,SS_assign_special_param(root));}/**IfthereisaLIMIT/OFFSETclause,addtheLIMITnode.*如果存在LIMIT/OFFSET子句,添加LIMIT节点*/if(limit_needed(parse)){path=(Path*)create_limit_path(root,final_rel,path,parse->limitOffset,parse->limitCount,offset_est,count_est);}/**IfthisisanINSERT/UPDATE/DELETE,andwe'renotbeingcalledfrom*inheritance_planner,addtheModifyTablenode.*如为INSERT/UPDATE/DELETE,而且不是从inheritance_planner函数中调用,则添加ModifyTable节点*/if(parse->commandType!=CMD_SELECT&&!inheritance_update)//非查询语句{List*withCheckOptionLists;List*returningLists;List*rowMarks;/**SetuptheWITHCHECKOPTIONandRETURNINGlists-of-lists,if*needed.*如需要,添加WITHCHECKOPTIONandRETURNING信息*/if(parse->withCheckOptions)withCheckOptionLists=list_make1(parse->withCheckOptions);elsewithCheckOptionLists=NIL;if(parse->returningList)returningLists=list_make1(parse->returningList);elsereturningLists=NIL;/**IftherewasaFOR[KEY]UPDATE/SHAREclause,theLockRowsnode*willhavedealtwithfetchingnon-lockedmarkedrows,elsewe*needtohaveModifyTabledothat.*如果存在FOR[KEY]UPDATE/SHARE子句,那么LockRows节点将处理获取非带锁标记的行,*否则我们需要使用ModifyTable来完成。*/if(parse->rowMarks)rowMarks=NIL;elserowMarks=root->rowMarks;path=(Path*)create_modifytable_path(root,final_rel,parse->commandType,parse->canSetTag,parse->resultRelation,NIL,false,list_make1_int(parse->resultRelation),list_make1(path),list_make1(root),withCheckOptionLists,returningLists,rowMarks,parse->onConflict,SS_assign_special_param(root));}/*Andshoveitintofinal_rel*///添加到final_rel中add_path(final_rel,path);}/**Generatepartialpathsforfinal_rel,too,xxwssssssssssssssssssifouterquerylevelsmight*beabletomakeuseofthem.*并行执行访问路径*/if(final_rel->consider_parallel&&root->query_level>1&&!limit_needed(parse)){Assert(!parse->rowMarks&&parse->commandType==CMD_SELECT);foreach(lc,current_rel->partial_pathlist){Path*partial_path=(Path*)lfirst(lc);add_partial_path(final_rel,partial_path);}}/**IfthereisanFDWthat'sresponsibleforallbaserelsofthequery,*letitconsideraddingForeignPaths.*如查询中存在FDW,添加ForeignPaths*/if(final_rel->fdwroutine&&final_rel->fdwroutine->GetForeignUpperPaths)final_rel->fdwroutine->GetForeignUpperPaths(root,UPPERREL_FINAL,current_rel,final_rel,NULL);/*Letextensionspossiblyaddsomemorepaths*///通过扩展添加访问路径if(create_upper_paths_hook)(*create_upper_paths_hook)(root,UPPERREL_FINAL,current_rel,final_rel,NULL);/*Note:currently,weleaveittocallerstodoset_cheapest()*///注意:目前的做法是让调用放来执行set_cheap()函数}
到此,关于“PostgreSQL中grouping_planner函数有什么作用”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。