PostgreSQL中用于初始化查询执行计划函数是哪个
本篇内容主要讲解“PostgreSQL中用于初始化查询执行计划函数是哪个”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“PostgreSQL中用于初始化查询执行计划函数是哪个”吧!
一、数据结构EState
执行器在调用时的主要工作状态
/*----------------*EStateinformation*EState信息*MasterworkingstateforanExecutorinvocation*执行器在调用时的主要工作状态*----------------*/typedefstructEState{NodeTagtype;//标记/*Basicstateforallquerytypes:*///所有查询类型的基础状态ScanDirectiones_direction;/*扫描方向,如向前/后等;currentscandirection*/Snapshotes_snapshot;/*时间条件(通过快照实现);timequaltouse*/Snapshotes_crosscheck_snapshot;/*RI的交叉检查时间条件;crosschecktimequalforRI*/List*es_range_table;/*RTE链表;ListofRangeTblEntry*/structRangeTblEntry**es_range_table_array;/*与链表等价的数组;equivalentarray*/Indexes_range_table_size;/*数组大小;sizeoftherangetablearrays*/Relation*es_relations;/*RTE中的Relation指针,如未Open则为NULL;*Arrayofper-range-table-entryRelation*pointers,orNULLifnotyetopened*/structExecRowMark**es_rowmarks;/*ExecRowMarks指针数组;*Arrayofper-range-table-entry*ExecRowMarks,orNULLifnone*/PlannedStmt*es_plannedstmt;/*计划树的最顶层PlannedStmt;linktotopofplantree*/constchar*es_sourceText;/*QueryDesc中的源文本;SourcetextfromQueryDesc*/JunkFilter*es_junkFilter;/*最顶层的JunkFilter;top-leveljunkfilter,ifany*//*Ifquerycaninsert/deletetuples,thecommandIDtomarkthemwith*///如查询可以插入/删除元组,这里记录了命令IDCommandIdes_output_cid;/*Infoabouttargettable(s)forinsert/update/deletequeries:*///insert/update/delete目标表信息ResultRelInfo*es_result_relations;/*ResultRelInfos数组;arrayofResultRelInfos*/intes_num_result_relations;/*数组大小;lengthofarray*/ResultRelInfo*es_result_relation_info;/*当前活动的数组;currentlyactivearrayelt*//**Infoaboutthepartitionroottable(s)forinsert/update/deletequeries*targetingpartitionedtables.Onlyleafpartitionsarementionedin*es_result_relations,butweneedaccesstotherootsforfiring*triggersandforruntimetuplerouting.*关于针对分区表的插入/更新/删除查询的分区根表的信息。*在es_result_relations中只提到了叶子分区,但是需要访问根表来触发触发器和运行时元组路由。*/ResultRelInfo*es_root_result_relations;/*ResultRelInfos数组;arrayofResultRelInfos*/intes_num_root_result_relations;/*数组大小;lengthofthearray*//**ThefollowinglistcontainsResultRelInfoscreatedbythetuplerouting*codeforpartitionsthatdon'talreadyhaveone.*下面的链表包含元组路由代码为没有分区的分区创建的ResultRelInfos。*/List*es_tuple_routing_result_relations;/*Stuffusedforfiringtriggers:*///用于触发触发器的信息List*es_trig_target_relations;/*与触发器相关的ResultRelInfos数组;trigger-onlyResultRelInfos*/TupleTableSlot*es_trig_tuple_slot;/*用于触发器输出的元组;fortriggeroutputtuples*/TupleTableSlot*es_trig_oldtup_slot;/*用于TriggerEnabled;forTriggerEnabled*/TupleTableSlot*es_trig_newtup_slot;/*用于TriggerEnabled;forTriggerEnabled*//*Parameterinfo:*///参数信息ParamListInfoes_param_list_info;/*外部参数值;valuesofexternalparams*/ParamExecData*es_param_exec_vals;/*内部参数值;valuesofinternalparams*/QueryEnvironment*es_queryEnv;/*查询环境;queryenvironment*//*Otherworkingstate:*///其他工作状态MemoryContextes_query_cxt;/*EState所在的内存上下文;per-querycontextinwhichEStatelives*/List*es_tupleTable;/*TupleTableSlots链表;ListofTupleTableSlots*/uint64es_processed;/*处理的元组数;#oftuplesprocessed*/Oides_lastoid;/*最后处理的oid(用于INSERT命令);lastoidprocessed(byINSERT)*/intes_top_eflags;/*传递给ExecutorStart函数的eflags参数;eflagspassedtoExecutorStart*/intes_instrument;/*InstrumentOption标记;ORofInstrumentOptionflags*/booles_finished;/*ExecutorFinish函数已完成则为T;truewhenExecutorFinishisdone*/List*es_exprcontexts;/*EState中的ExprContexts链表;ListofExprContextswithinEState*/List*es_subplanstates;/*SubPlans的PlanState链表;ListofPlanStateforSubPlans*/List*es_auxmodifytables;/*第二个ModifyTableStates链表;ListofsecondaryModifyTableStates*//**thisExprContextisforper-output-tupleoperations,suchasconstraint*checksandindex-valuecomputations.Itwillberesetforeachoutput*tuple.Notethatitwillbecreatedonlyifneeded.*这个ExprContext用于元组输出操作,例如约束检查和索引值计算。它在每个输出元组时重置。*注意,只有在需要时才会创建它。*/ExprContext*es_per_tuple_exprcontext;/**Thesefieldsareforre-evaluatingplanqualswhenanupdatedtupleis*substitutedinREADCOMMITTEDmode.es_epqTuple[]containstuplesthat*scanplannodesshouldreturninsteadofwhateverthey'dnormally*return,orNULLifnothingtoreturn;es_epqTupleSet[]istrueifa*particulararrayentryisvalid;andes_epqScanDone[]isstateto*rememberifthetuplehasbeenreturnedalready.Arraysareofsize*es_range_table_sizeandareindexedbyscannodescanrelid-1.*这些字段用于在读取提交模式中替换更新后的元组时重新评估计划的条件quals。*es_epqTuple[]数组包含扫描计划节点应该返回的元组,而不是它们通常返回的任何值,如果没有返回值,则为NULL;*如果特定数组条目有效,则es_epqTupleSet[]为真;es_epqScanDone[]是状态,用来记住元组是否已经返回。*数组大小为es_range_table_size,通过扫描节点scanrelid-1进行索引。*/HeapTuple*es_epqTuple;/*EPQ替换元组的数组;arrayofEPQsubstitutetuples*/bool*es_epqTupleSet;/*如EPQ元组已提供,则为T;trueifEPQtupleisprovided*/bool*es_epqScanDone;/*如EPQ元组已获取,则为T;trueifEPQtuplehasbeenfetched*/booles_use_parallel_mode;/*能否使用并行worker?canweuseparallelworkers?*//*Theper-querysharedmemoryareatouseforparallelexecution.*///用于并行执行的每个查询共享内存区域。structdsa_area*es_query_dsa;/**JITinformation.es_jit_flagsindicateswhetherJITshouldbeperformed*andwithwhichoptions.es_jitiscreatedon-demandwhenJITingis*performed.*JIT的信息。es_jit_flags指示是否应该执行JIT以及使用哪些选项。在执行JITing时,按需创建es_jit。**es_jit_combined_instristhethecombined,ondemandallocated,*instrumentationfromallworkers.Theleader'sinstrumentationiskept*separate,andiscombinedondemandbyExplainPrintJITSummary().*es_jit_combined_instr是所有workers根据需要分配的组合工具。*leader的插装是独立的,根据需要由ExplainPrintJITSummary()组合。*/intes_jit_flags;structJitContext*es_jit;structJitInstrumentation*es_jit_worker_instr;}EState;
PlanState
PlanState是所有PlanState-type节点的虚父类(请参照面向对象的虚类)
/*----------------*PlanStatenode*PlanState节点*WeneveractuallyinstantiateanyPlanStatenodes;thisisjustthecommon*abstractsuperclassforallPlanState-typenodes.*实际上并没有实例化PlanState节点;*这是所有PlanState-type节点的虚父类(请参照面向对象的虚类).*----------------*/typedefstructPlanState{NodeTagtype;//节点类型Plan*plan;/*绑定的计划节点;associatedPlannode*/EState*state;/*在执行期,指向top-level计划的EState指针*atexecutiontime,statesofindividual*nodespointtooneEStateforthewhole*top-levelplan*/ExecProcNodeMtdExecProcNode;/*执行返回下一个元组的函数;functiontoreturnnexttuple*/ExecProcNodeMtdExecProcNodeReal;/*如果ExecProcNode是封装器,则这个变量是实际的函数;*actualfunction,ifaboveisa*wrapper*/Instrumentation*instrument;/*该节点可选的运行期统计信息;Optionalruntimestatsforthisnode*/WorkerInstrumentation*worker_instrument;/*每个worker的instrumentation;per-workerinstrumentation*//*Per-workerJITinstrumentation*///worker相应的JITinstrumentationstructSharedJitInstrumentation*worker_jit_instrument;/**CommonstructuraldataforallPlantypes.Theselinkstosubsidiary*statetreesparallellinksintheassociatedplantree(exceptforthe*subPlanlist,whichdoesnotexistintheplantree).*所有Plan类型均有的数据结构;*这些链接到附属状态通过并行的方式链接到关联的计划树中(除了计划树中不存在的子计划链表)。*/ExprState*qual;/*布尔条件;booleanqualcondition*/structPlanState*lefttree;/*输入的计划树,包括左树&右树;inputplantree(s)*/structPlanState*righttree;List*initPlan;/*初始的SubPlanState节点链表;*InitSubPlanStatenodes(un-correlatedexpr*subselects)*/List*subPlan;/*在表达式中的subPlan链表;SubPlanStatenodesinmyexpressions*//**Stateformanagementofparameter-change-drivenrescanning*参数改变驱动的重新扫描管理状态*/Bitmapset*chgParam;/*changedParams的IDs集合(用于NestLoop连接);setofIDsofchangedParams*//**Otherrun-timestateneededbymostifnotallnodetypes.*大多数(如果不是所有)节点类型都需要的其他运行时状态。*/TupleDescps_ResultTupleDesc;/*节点的返回类型;node'sreturntype*/TupleTableSlot*ps_ResultTupleSlot;/*结果元组的slot;slotformyresulttuples*/ExprContext*ps_ExprContext;/*节点的表达式解析上下文;node'sexpression-evaluationcontext*/ProjectionInfo*ps_ProjInfo;/*元组投影信息;infofordoingtupleprojection*//**Scanslot'sdescriptorifknown.Thisisabitofahack,butotherwise*it'shardforexpressioncompilationtooptimizebasedonthe*descriptor,withoutencodingknowledgeaboutallexecutornodes.*Scanslot描述符。*这有点笨拙,但是如果不编码关于所有执行器节点的知识,那么表达式编译就很难基于描述符进行优化。*/TupleDescscandesc;}PlanState;二、源码解读
InitPlan函数初始化查询执行计划:打开文件/分配存储空间并启动规则管理器.
/*----------------------------------------------------------------*InitPlan**Initializesthequeryplan:openfiles,allocatestorage*andstartuptherulemanager*初始化查询执行计划:打开文件/分配存储空间并启动规则管理器*----------------------------------------------------------------*/staticvoidInitPlan(QueryDesc*queryDesc,inteflags){CmdTypeoperation=queryDesc->operation;//命令类型PlannedStmt*plannedstmt=queryDesc->plannedstmt;//已规划的语句指针Plan*plan=plannedstmt->planTree;//计划树List*rangeTable=plannedstmt->rtable;//RTE链表EState*estate=queryDesc->estate;//参见数据结构PlanState*planstate;//参见数据结构TupleDesctupType;//参见数据结构ListCell*l;inti;/**Dopermissionschecks*权限检查*/ExecCheckRTPerms(rangeTable,true);/**initializethenode'sexecutionstate*初始化节点执行状态*/ExecInitRangeTable(estate,rangeTable);estate->es_plannedstmt=plannedstmt;/**InitializeResultRelInfodatastructures,andopentheresultrels.*初始化ResultRelInfo数据结构,打开结果rels*/if(plannedstmt->resultRelations)//存在resultRelations{List*resultRelations=plannedstmt->resultRelations;//结果Relation链表intnumResultRelations=list_length(resultRelations);//链表大小ResultRelInfo*resultRelInfos;//ResultRelInfo数组ResultRelInfo*resultRelInfo;//ResultRelInfo指针resultRelInfos=(ResultRelInfo*)palloc(numResultRelations*sizeof(ResultRelInfo));//分配空间resultRelInfo=resultRelInfos;//指针赋值foreach(l,resultRelations)//遍历链表{IndexresultRelationIndex=lfirst_int(l);RelationresultRelation;resultRelation=ExecGetRangeTableRelation(estate,resultRelationIndex);//获取结果RelationInitResultRelInfo(resultRelInfo,resultRelation,resultRelationIndex,NULL,estate->es_instrument);//初始化ResultRelInforesultRelInfo++;//处理下一个ResultRelInfo}estate->es_result_relations=resultRelInfos;//赋值estate->es_num_result_relations=numResultRelations;/*es_result_relation_infoisNULLexceptwhenwithinModifyTable*///设置es_result_relation_info为NULL,除了ModifyTableestate->es_result_relation_info=NULL;/**Inthepartitionedresultrelationcase,alsobuildResultRelInfos*forallthepartitionedtableroots,becausewewillneedthemto*firestatement-leveltriggers,ifany.*在分区结果关系这种情况中,还为所有分区表根构建ResultRelInfos,*因为我们需要它们触发语句级别的触发器(如果有的话)。*/if(plannedstmt->rootResultRelations)//存在rootResultRelations(并行处理){intnum_roots=list_length(plannedstmt->rootResultRelations);resultRelInfos=(ResultRelInfo*)palloc(num_roots*sizeof(ResultRelInfo));resultRelInfo=resultRelInfos;foreach(l,plannedstmt->rootResultRelations){IndexresultRelIndex=lfirst_int(l);RelationresultRelDesc;resultRelDesc=ExecGetRangeTableRelation(estate,resultRelIndex);InitResultRelInfo(resultRelInfo,resultRelDesc,resultRelIndex,NULL,estate->es_instrument);resultRelInfo++;}estate->es_root_result_relations=resultRelInfos;estate->es_num_root_result_relations=num_roots;}else{estate->es_root_result_relations=NULL;estate->es_num_root_result_relations=0;}}else//不存在resultRelations{/**ifnoresultrelation,thensetstateappropriately*无resultRelations,设置相应的信息为NULL或为0*/estate->es_result_relations=NULL;estate->es_num_result_relations=0;estate->es_result_relation_info=NULL;estate->es_root_result_relations=NULL;estate->es_num_root_result_relations=0;}/**Next,buildtheExecRowMarkarrayfromthePlanRowMark(s),ifany.*下一步,利用PlanRowMark(s)创建ExecRowMark数组*/if(plannedstmt->rowMarks)//如存在rowMarks{estate->es_rowmarks=(ExecRowMark**)palloc0(estate->es_range_table_size*sizeof(ExecRowMark*));foreach(l,plannedstmt->rowMarks){PlanRowMark*rc=(PlanRowMark*)lfirst(l);Oidrelid;Relationrelation;ExecRowMark*erm;/*ignore"parent"rowmarks;theyareirrelevantatruntime*/if(rc->isParent)continue;/*getrelation'sOID(willproduceInvalidOidifsubquery)*/relid=exec_rt_fetch(rc->rti,estate)->relid;/*openrelation,ifweneedtoaccessitforthismarktype*/switch(rc->markType){caseROW_MARK_EXCLUSIVE:caseROW_MARK_NOKEYEXCLUSIVE:caseROW_MARK_SHARE:caseROW_MARK_KEYSHARE:caseROW_MARK_REFERENCE:relation=ExecGetRangeTableRelation(estate,rc->rti);break;caseROW_MARK_COPY:/*nophysicaltableaccessisrequired*/relation=NULL;break;default:elog(ERROR,"unrecognizedmarkType:%d",rc->markType);relation=NULL;/*keepcompilerquiet*/break;}/*Checkthatrelationisalegaltargetformarking*/if(relation)CheckValidRowMarkRel(relation,rc->markType);erm=(ExecRowMark*)palloc(sizeof(ExecRowMark));erm->relation=relation;erm->relid=relid;erm->rti=rc->rti;erm->prti=rc->prti;erm->rowmarkId=rc->rowmarkId;erm->markType=rc->markType;erm->strength=rc->strength;erm->waitPolicy=rc->waitPolicy;erm->ermActive=false;ItemPointerSetInvalid(&(erm->curCtid));erm->ermExtra=NULL;Assert(erm->rti>0&&erm->rti<=estate->es_range_table_size&&estate->es_rowmarks[erm->rti-1]==NULL);estate->es_rowmarks[erm->rti-1]=erm;}}/**Initializetheexecutor'stupletabletoempty.*初始化执行器的元组表为NULL*/estate->es_tupleTable=NIL;estate->es_trig_tuple_slot=NULL;estate->es_trig_oldtup_slot=NULL;estate->es_trig_newtup_slot=NULL;/*markEvalPlanQualnotactive*///标记EvalPlanQual为非活动模式estate->es_epqTuple=NULL;estate->es_epqTupleSet=NULL;estate->es_epqScanDone=NULL;/**InitializeprivatestateinformationforeachSubPlan.Wemustdothis*beforerunningExecInitNodeonthemainquerytree,since*ExecInitSubPlanexpectstobeabletofindtheseentries.*为每个子计划初始化私有状态信息。*在主查询树上运行ExecInitNode之前,必须这样做,因为ExecInitSubPlan希望能够找到这些条目。*/Assert(estate->es_subplanstates==NIL);i=1;/*subplan索引计数从1开始;subplanindicescountfrom1*/foreach(l,plannedstmt->subplans)//遍历subplans{Plan*subplan=(Plan*)lfirst(l);PlanState*subplanstate;intsp_eflags;/**AsubplanwillneverneedtodoBACKWARDscannorMARK/RESTORE.If*itisaparameterlesssubplan(notinitplan),wesuggestthatitbe*preparedtohandleREWINDefficiently;otherwisethereisnoneed.*子计划永远不需要执行向后扫描或标记/恢复。*如果它是一个无参数的子计划(不是initplan),建议它准备好有效地处理向后扫描;否则就没有必要了。*/sp_eflags=eflags&(EXEC_FLAG_EXPLAIN_ONLY|EXEC_FLAG_WITH_NO_DATA);//设置sp_eflagsif(bms_is_member(i,plannedstmt->rewindPlanIDs))sp_eflags|=EXEC_FLAG_REWIND;subplanstate=ExecInitNode(subplan,estate,sp_eflags);//执行Plan节点初始化过程estate->es_subplanstates=lappend(estate->es_subplanstates,subplanstate);i++;}/**Initializetheprivatestateinformationforallthenodesinthequery*tree.Thisopensfiles,allocatesstorageandleavesusreadytostart*processingtuples.*为查询树中的所有节点初始化私有状态信息。*这将打开文件、分配存储并让我们准备好开始处理元组。*/planstate=ExecInitNode(plan,estate,eflags);//执行Plan节点初始化过程/**Getthetupledescriptordescribingthetypeoftuplestoreturn.*获取元组描述(返回的元组类型等)*/tupType=ExecGetResultType(planstate);/**Initializethejunkfilterifneeded.SELECTqueriesneedafilterif*thereareanyjunkattrsinthetop-leveltlist.*如需要,初始化垃圾过滤器。如果顶层的tlist中有任何垃圾标识,SELECT查询需要一个过滤器。*/if(operation==CMD_SELECT)//SELECT命令{booljunk_filter_needed=false;ListCell*tlist;foreach(tlist,plan->targetlist)//遍历tlist{TargetEntry*tle=(TargetEntry*)lfirst(tlist);if(tle->resjunk)//如需要垃圾过滤器{junk_filter_needed=true;//设置为Tbreak;}}if(junk_filter_needed){JunkFilter*j;j=ExecInitJunkFilter(planstate->plan->targetlist,tupType->tdhasoid,ExecInitExtraTupleSlot(estate,NULL));//初始化estate->es_junkFilter=j;/*Wanttoreturnthecleanedtupletype*///期望返回已清理的元组类型tupType=j->jf_cleanTupType;}}//赋值queryDesc->tupDesc=tupType;queryDesc->planstate=planstate;}三、跟踪分析
测试脚本如下
testdb=#explainselectdw.*,grjf.grbh,grjf.xm,grjf.ny,grjf.jetestdb-#fromt_dwxxdw,lateral(selectgr.grbh,gr.xm,jf.ny,jf.jetestdb(#fromt_grxxgrinnerjoint_jfxxjftestdb(#ongr.dwbh=dw.dwbhtestdb(#andgr.grbh=jf.grbh)grjftestdb-#orderbydw.dwbh;QUERYPLAN------------------------------------------------------------------------------------------Sort(cost=20070.93..20320.93rows=100000width=47)SortKey:dw.dwbh->HashJoin(cost=3754.00..8689.61rows=100000width=47)HashCond:((gr.dwbh)::text=(dw.dwbh)::text)->HashJoin(cost=3465.00..8138.00rows=100000width=31)HashCond:((jf.grbh)::text=(gr.grbh)::text)->SeqScanont_jfxxjf(cost=0.00..1637.00rows=100000width=20)->Hash(cost=1726.00..1726.00rows=100000width=16)->SeqScanont_grxxgr(cost=0.00..1726.00rows=100000width=16)->Hash(cost=164.00..164.00rows=10000width=20)->SeqScanont_dwxxdw(cost=0.00..164.00rows=10000width=20)(11rows)
启动gdb,设置断点,进入InitPlan
(gdb)bInitPlanBreakpoint1at0x6d9df2:fileexecMain.c,line808.(gdb)cContinuing.Breakpoint1,InitPlan(queryDesc=0x20838b8,eflags=16)atexecMain.c:808warning:Sourcefileismorerecentthanexecutable.808CmdTypeoperation=queryDesc->operation;
输入参数
(gdb)p*queryDesc$1={operation=CMD_SELECT,plannedstmt=0x207e6c0,sourceText=0x1f96eb8"selectdw.*,grjf.grbh,grjf.xm,grjf.ny,grjf.je\nfromt_dwxxdw,lateral(selectgr.grbh,gr.xm,jf.ny,jf.je\n",''<repeats24times>,"fromt_grxxgrinnerjoint_jfxxjf\n",''<repeats34times>...,snapshot=0x1fba8e0,crosscheck_snapshot=0x0,dest=0xf8f280<donothingDR>,params=0x0,queryEnv=0x0,instrument_options=0,tupDesc=0x0,estate=0x207f898,planstate=0x0,already_executed=false,totaltime=0x0}(gdb)peflags$2=16
变量赋值,PlannedStmt的详细数据结构先前章节已有解释,请参见相关章节.
(gdb)n809PlannedStmt*plannedstmt=queryDesc->plannedstmt;(gdb)810Plan*plan=plannedstmt->planTree;(gdb)811List*rangeTable=plannedstmt->rtable;(gdb)n812EState*estate=queryDesc->estate;(gdb)821ExecCheckRTPerms(rangeTable,true);(gdb)p*plannedstmt$3={type=T_PlannedStmt,commandType=CMD_SELECT,queryId=0,hasReturning=false,hasModifyingCTE=false,canSetTag=true,transientPlan=false,dependsOnRole=false,parallelModeNeeded=false,jitFlags=0,planTree=0x20788f8,rtable=0x207c568,resultRelations=0x0,nonleafResultRelations=0x0,rootResultRelations=0x0,subplans=0x0,rewindPlanIDs=0x0,rowMarks=0x0,relationOids=0x207c5c8,invalItems=0x0,paramExecTypes=0x0,utilityStmt=0x0,stmt_location=0,stmt_len=313}(gdb)p*plan$4={type=T_Sort,startup_cost=20070.931487218411,total_cost=20320.931487218411,plan_rows=100000,plan_width=47,parallel_aware=false,parallel_safe=true,plan_node_id=0,targetlist=0x207cc28,qual=0x0,lefttree=0x207c090,righttree=0x0,initPlan=0x0,extParam=0x0,allParam=0x0}(gdb)p*estate$5={type=T_EState,es_direction=ForwardScanDirection,es_snapshot=0x1fba8e0,es_crosscheck_snapshot=0x0,es_range_table=0x0,es_plannedstmt=0x0,es_sourceText=0x1f96eb8"selectdw.*,grjf.grbh,grjf.xm,grjf.ny,grjf.je\nfromt_dwxxdw,lateral(selectgr.grbh,gr.xm,jf.ny,jf.je\n",''<repeats24times>,"fromt_grxxgrinnerjoint_jfxxjf\n",''<repeats34times>...,es_junkFilter=0x0,es_output_cid=0,es_result_relations=0x0,es_num_result_relations=0,es_result_relation_info=0x0,es_root_result_relations=0x0,es_num_root_result_relations=0,es_tuple_routing_result_relations=0x0,es_trig_target_relations=0x0,es_trig_tuple_slot=0x0,es_trig_oldtup_slot=0x0,es_trig_newtup_slot=0x0,es_param_list_info=0x0,es_param_exec_vals=0x0,es_queryEnv=0x0,es_query_cxt=0x207f780,es_tupleTable=0x0,es_rowMarks=0x0,es_processed=0,es_lastoid=0,es_top_eflags=16,es_instrument=0,es_finished=false,es_exprcontexts=0x0,es_subplanstates=0x0,es_auxmodifytables=0x0,es_per_tuple_exprcontext=0x0,es_epqTuple=0x0,es_epqTupleSet=0x0,es_epqScanDone=0x0,es_use_parallel_mode=false,es_query_dsa=0x0,es_jit_flags=0,es_jit=0x0,es_jit_worker_instr=0x0}
RTE链表,一共有5个Item,3个基础关系RTE_RELATION(1/3/4),1个RTE_SUBQUERY(2号),1个RTE_JOIN(5号)
(gdb)n826estate->es_range_table=rangeTable;(gdb)p*rangeTable$6={type=T_List,length=5,head=0x207c540,tail=0x207cb28}(gdb)p*(RangeTblEntry*)rangeTable->head->data.ptr_value$9={type=T_RangeTblEntry,rtekind=RTE_RELATION,relid=16734,relkind=114'r',tablesample=0x0,subquery=0x0,security_barrier=false,jointype=JOIN_INNER,joinaliasvars=0x0,functions=0x0,funcordinality=false,tablefunc=0x0,values_lists=0x0,ctename=0x0,ctelevelsup=0,self_reference=false,coltypes=0x0,coltypmods=0x0,colcollations=0x0,enrname=0x0,enrtuples=0,alias=0x1f98448,eref=0x1fbdd20,lateral=false,inh=false,inFromCl=true,requiredPerms=2,checkAsUser=0,selectedCols=0x2054de8,insertedCols=0x0,updatedCols=0x0,securityQuals=0x0}...
没有结果Relation,执行相应的处理逻辑
(gdb)835if(plannedstmt->resultRelations)(gdb)pplannedstmt->resultRelations$14=(List*)0x0(gdb)n922estate->es_result_relations=NULL;(gdb)923estate->es_num_result_relations=0;(gdb)924estate->es_result_relation_info=NULL;(gdb)925estate->es_root_result_relations=NULL;(gdb)926estate->es_num_root_result_relations=0;
不存在rowMarks(for update)
(gdb)n939foreach(l,plannedstmt->rowMarks)(gdb)pplannedstmt->rowMarks$15=(List*)0x0(gdb)pplannedstmt->rowMarks$16=(List*)0x0(gdb)n1000estate->es_tupleTable=NIL;
执行赋值
(gdb)n1001estate->es_trig_tuple_slot=NULL;(gdb)1002estate->es_trig_oldtup_slot=NULL;...
没有subplans
(gdb)n1017foreach(l,plannedstmt->subplans)(gdb)p*plannedstmt->subplansCannotaccessmemoryataddress0x0(gdb)n
初始化节点(执行ExecInitNode)和获取TupleType
(gdb)n1046planstate=ExecInitNode(plan,estate,eflags);(gdb)n1051tupType=ExecGetResultType(planstate);(gdb)1057if(operation==CMD_SELECT)(gdb)p*planstate$17={type=T_SortState,plan=0x20788f8,state=0x207f898,ExecProcNode=0x6e41bb<ExecProcNodeFirst>,ExecProcNodeReal=0x716144<ExecSort>,instrument=0x0,worker_instrument=0x0,worker_jit_instrument=0x0,qual=0x0,lefttree=0x207fbc8,righttree=0x0,initPlan=0x0,subPlan=0x0,chgParam=0x0,ps_ResultTupleSlot=0x2090dc0,ps_ExprContext=0x0,ps_ProjInfo=0x0,scandesc=0x208e920}(gdb)ptupType$18=(TupleDesc)0x20909a8(gdb)p*tupType$19={natts=7,tdtypeid=2249,tdtypmod=-1,tdhasoid=false,tdrefcount=-1,constr=0x0,attrs=0x20909c8}
判断是否需要垃圾过滤器
(gdb)n1059booljunk_filter_needed=false;(gdb)1062foreach(tlist,plan->targetlist)
不需要junk filter
(gdb)1073if(junk_filter_needed)
赋值,结束调用
(gdb)1087queryDesc->tupDesc=tupType;(gdb)1088queryDesc->planstate=planstate;(gdb)1089}(gdb)standard_ExecutorStart(queryDesc=0x20838b8,eflags=16)atexecMain.c:267267MemoryContextSwitchTo(oldcontext);(gdb)p*queryDesc$21={operation=CMD_SELECT,plannedstmt=0x207e6c0,sourceText=0x1f96eb8"selectdw.*,grjf.grbh,grjf.xm,grjf.ny,grjf.je\nfromt_dwxxdw,lateral(selectgr.grbh,gr.xm,jf.ny,jf.je\n",''<repeats24times>,"fromt_grxxgrinnerjoint_jfxxjf\n",''<repeats34times>...,snapshot=0x1fba8e0,crosscheck_snapshot=0x0,dest=0xf8f280<donothingDR>,params=0x0,queryEnv=0x0,instrument_options=0,tupDesc=0x20909a8,estate=0x207f898,planstate=0x207fab0,already_executed=false,totaltime=0x0}
到此,相信大家对“PostgreSQL中用于初始化查询执行计划函数是哪个”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。