PostgreSQL查询优化中如何实现上拉子链接
本篇内容介绍了“PostgreSQL查询优化中如何实现上拉子链接”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
查询树
/**Recursethroughjointreenodesforpull_up_sublinks()**Inadditiontoreturningthepossibly-modifiedjointreenode,wereturn*arelidssetofthecontainedrelsinto*relids.*/staticNode*pull_up_sublinks_jointree_recurse(PlannerInfo*root,Node*jtnode,Relids*relids){if(jtnode==NULL){*relids=NULL;}elseif(IsA(jtnode,RangeTblRef))//如为RangeTblRef类型{intvarno=((RangeTblRef*)jtnode)->rtindex;*relids=bms_make_singleton(varno);/*jtnodeisreturnedunmodified*/}elseif(IsA(jtnode,FromExpr))//如为FromExpr类型{FromExpr*f=(FromExpr*)jtnode;List*newfromlist=NIL;Relidsfrelids=NULL;FromExpr*newf;Node*jtlink;ListCell*l;/*First,recursetoprocesschildrenandcollecttheirrelids*/foreach(l,f->fromlist)//{Node*newchild;Relidschildrelids;//对fromlist中的元素执行上拉操作//如能够上拉,则把子查询从WHERE子句中提升到FROM子句,newchild作为连接的一部分newchild=pull_up_sublinks_jointree_recurse(root,lfirst(l),&childrelids);newfromlist=lappend(newfromlist,newchild);frelids=bms_join(frelids,childrelids);}/*BuildthereplacementFromExpr;noqualsyet*/newf=makeFromExpr(newfromlist,NULL);//创建新的FromExpr/*Setupalinkrepresentingtherebuiltjointree*/jtlink=(Node*)newf;/*Nowprocessqual---allchildrenareavailableforuse*///处理子链接中的表达式//newf(指针,相当于jtlink)newf->quals=pull_up_sublinks_qual_recurse(root,f->quals,&jtlink,frelids,NULL,NULL);///**Notethattheresultwillbeeithernewf,orastackofJoinExprs*withnewfatthebase.Werelyonsubsequentoptimizationstepsto*flattenthisandrearrangethejoinsasneeded.**Althoughwecouldincludethepulled-upsubqueriesinthereturned*relids,there'snoneedsinceupperqualscouldn'trefertotheir*outputsanyway.*/*relids=frelids;//设置相关的relidsjtnode=jtlink;//返回值}elseif(IsA(jtnode,JoinExpr)){JoinExpr*j;Relidsleftrelids;Relidsrightrelids;Node*jtlink;/**Makeamodifiablecopyofjoinnode,butdon'tbothercopyingits*subnodes(yet).*/j=(JoinExpr*)palloc(sizeof(JoinExpr));memcpy(j,jtnode,sizeof(JoinExpr));jtlink=(Node*)j;/*Recursetoprocesschildrenandcollecttheirrelids*///递归处理左边&右边子树j->larg=pull_up_sublinks_jointree_recurse(root,j->larg,&leftrelids);j->rarg=pull_up_sublinks_jointree_recurse(root,j->rarg,&rightrelids);/**Nowprocessqual,showingappropriatechildrelidsasavailable,*andattachanypulled-upjointreeitemsattherightplace.Inthe*inner-joincaseweputnewJoinExprsabovetheexistingone(much*asforaFromExpr-stylejoin).Inouter-joincasesthenew*JoinExprsmustgointothenullablesideoftheouterjoin.The*pointoftheavailable_relsmachinationsistoensurethatweonly*pullupqualsforwhichthat'sokay.**Wedon'texpecttoseeanypre-existingJOIN_SEMIorJOIN_ANTI*nodeshere.*/switch(j->jointype){caseJOIN_INNER:j->quals=pull_up_sublinks_qual_recurse(root,j->quals,&jtlink,bms_union(leftrelids,rightrelids),NULL,NULL);break;caseJOIN_LEFT:j->quals=pull_up_sublinks_qual_recurse(root,j->quals,&j->rarg,rightrelids,NULL,NULL);break;caseJOIN_FULL:/*can'tdoanythingwithfull-joinquals*/break;caseJOIN_RIGHT:j->quals=pull_up_sublinks_qual_recurse(root,j->quals,&j->larg,leftrelids,NULL,NULL);break;default:elog(ERROR,"unrecognizedjointype:%d",(int)j->jointype);break;}/**Althoughwecouldincludethepulled-upsubqueriesinthereturned*relids,there'snoneedsinceupperqualscouldn'trefertotheir*outputsanyway.Butwe*do*needtoincludethejoin'sownrtindex*becausewehaven'tyetcollapsedjoinaliasvariables,soupper*levelswouldmistakenlythinktheycouldn'tusereferencestothis*join.*/*relids=bms_join(leftrelids,rightrelids);if(j->rtindex)*relids=bms_add_member(*relids,j->rtindex);jtnode=jtlink;}elseelog(ERROR,"unrecognizednodetype:%d",(int)nodeTag(jtnode));returnjtnode;}
pull_up_sublinks_qual_recurse
/**Recursethroughtop-levelqualnodesforpull_up_sublinks()**jtlink1pointstothelinkinthejointreewhereanynewJoinExprsshould*beinsertediftheyreferenceavailable_rels1(i.e.,available_rels1*denotestherelationspresentunderneathjtlink1).Optionally,jtlink2can*pointtoasecondlinkwherenewJoinExprsshouldbeinsertedifthey*referenceavailable_rels2(passNULLforboththoseargumentsifnotused).*NotethatSubLinksreferencingbothsetsofvariablescannotbeoptimized.*Ifwefindmultiplepull-up-ableSubLinks,they'llgetstackedontojtlink1*and/orjtlink2intheorderweencounterthem.Werelyonsubsequent*optimizationtorearrangethestackifappropriate.**Returnsthereplacementqualnode,orNULLifthequalshouldberemoved.*/staticNode*pull_up_sublinks_qual_recurse(PlannerInfo*root,Node*node,Node**jtlink1,Relidsavailable_rels1,Node**jtlink2,Relidsavailable_rels2){if(node==NULL)returnNULL;if(IsA(node,SubLink))//子链接{SubLink*sublink=(SubLink*)node;JoinExpr*j;Relidschild_rels;/*IsitaconvertibleANYorEXISTSclause?*/if(sublink->subLinkType==ANY_SUBLINK)//ANY子链接{if((j=convert_ANY_sublink_to_join(root,sublink,available_rels1))!=NULL){/*Yes;insertthenewjoinnodeintothejointree*/j->larg=*jtlink1;*jtlink1=(Node*)j;/*Recursivelyprocesspulled-upjointreenodes*/j->rarg=pull_up_sublinks_jointree_recurse(root,j->rarg,&child_rels);/**Nowrecursivelyprocessthepulled-upquals.Anyinserted*joinscangetstackedontoeitherj->largorj->rarg,*dependingonwhichrelstheyreference.*/j->quals=pull_up_sublinks_qual_recurse(root,j->quals,&j->larg,available_rels1,&j->rarg,child_rels);/*ReturnNULLrepresentingconstantTRUE*/returnNULL;}if(available_rels2!=NULL&&(j=convert_ANY_sublink_to_join(root,sublink,available_rels2))!=NULL){/*Yes;insertthenewjoinnodeintothejointree*/j->larg=*jtlink2;*jtlink2=(Node*)j;/*Recursivelyprocesspulled-upjointreenodes*/j->rarg=pull_up_sublinks_jointree_recurse(root,j->rarg,&child_rels);/**Nowrecursivelyprocessthepulled-upquals.Anyinserted*joinscangetstackedontoeitherj->largorj->rarg,*dependingonwhichrelstheyreference.*/j->quals=pull_up_sublinks_qual_recurse(root,j->quals,&j->larg,available_rels2,&j->rarg,child_rels);/*ReturnNULLrepresentingconstantTRUE*/returnNULL;}}elseif(sublink->subLinkType==EXISTS_SUBLINK)//EXISTS子链接{if((j=convert_EXISTS_sublink_to_join(root,sublink,false,available_rels1))!=NULL){/*Yes;insertthenewjoinnodeintothejointree*/j->larg=*jtlink1;*jtlink1=(Node*)j;/*Recursivelyprocesspulled-upjointreenodes*/j->rarg=pull_up_sublinks_jointree_recurse(root,j->rarg,&child_rels);/**Nowrecursivelyprocessthepulled-upquals.Anyinserted*joinscangetstackedontoeitherj->largorj->rarg,*dependingonwhichrelstheyreference.*/j->quals=pull_up_sublinks_qual_recurse(root,j->quals,&j->larg,available_rels1,&j->rarg,child_rels);/*ReturnNULLrepresentingconstantTRUE*/returnNULL;}if(available_rels2!=NULL&&(j=convert_EXISTS_sublink_to_join(root,sublink,false,available_rels2))!=NULL){/*Yes;insertthenewjoinnodeintothejointree*/j->larg=*jtlink2;*jtlink2=(Node*)j;/*Recursivelyprocesspulled-upjointreenodes*/j->rarg=pull_up_sublinks_jointree_recurse(root,j->rarg,&child_rels);/**Nowrecursivelyprocessthepulled-upquals.Anyinserted*joinscangetstackedontoeitherj->largorj->rarg,*dependingonwhichrelstheyreference.*/j->quals=pull_up_sublinks_qual_recurse(root,j->quals,&j->larg,available_rels2,&j->rarg,child_rels);/*ReturnNULLrepresentingconstantTRUE*/returnNULL;}}/*Elsereturnitunmodified*/returnnode;}if(not_clause(node))//NOT语句{/*IftheimmediateargumentofNOTisEXISTS,trytoconvert*/SubLink*sublink=(SubLink*)get_notclausearg((Expr*)node);JoinExpr*j;Relidschild_rels;if(sublink&&IsA(sublink,SubLink)){if(sublink->subLinkType==EXISTS_SUBLINK){if((j=convert_EXISTS_sublink_to_join(root,sublink,true,available_rels1))!=NULL){/*Yes;insertthenewjoinnodeintothejointree*/j->larg=*jtlink1;*jtlink1=(Node*)j;/*Recursivelyprocesspulled-upjointreenodes*/j->rarg=pull_up_sublinks_jointree_recurse(root,j->rarg,&child_rels);/**Nowrecursivelyprocessthepulled-upquals.Because*weareunderneathaNOT,wecan'tpullupsublinksthat*referencetheleft-handstuff,butit'sstillokayto*pullupsublinksreferencingj->rarg.*/j->quals=pull_up_sublinks_qual_recurse(root,j->quals,&j->rarg,child_rels,NULL,NULL);/*ReturnNULLrepresentingconstantTRUE*/returnNULL;}if(available_rels2!=NULL&&(j=convert_EXISTS_sublink_to_join(root,sublink,true,available_rels2))!=NULL){/*Yes;insertthenewjoinnodeintothejointree*/j->larg=*jtlink2;*jtlink2=(Node*)j;/*Recursivelyprocesspulled-upjointreenodes*/j->rarg=pull_up_sublinks_jointree_recurse(root,j->rarg,&child_rels);/**Nowrecursivelyprocessthepulled-upquals.Because*weareunderneathaNOT,wecan'tpullupsublinksthat*referencetheleft-handstuff,butit'sstillokayto*pullupsublinksreferencingj->rarg.*/j->quals=pull_up_sublinks_qual_recurse(root,j->quals,&j->rarg,child_rels,NULL,NULL);/*ReturnNULLrepresentingconstantTRUE*/returnNULL;}}}/*Elsereturnitunmodified*/returnnode;}if(and_clause(node))//AND语句{/*RecurseintoANDclause*/List*newclauses=NIL;ListCell*l;foreach(l,((BoolExpr*)node)->args){Node*oldclause=(Node*)lfirst(l);Node*newclause;newclause=pull_up_sublinks_qual_recurse(root,oldclause,jtlink1,available_rels1,jtlink2,available_rels2);if(newclause)newclauses=lappend(newclauses,newclause);}/*Wemighthavegotbackfewerclausesthanwestartedwith*/if(newclauses==NIL)returnNULL;elseif(list_length(newclauses)==1)return(Node*)linitial(newclauses);elsereturn(Node*)make_andclause(newclauses);}/*StopifnotanAND*/returnnode;}
convert_ANY_sublink_to_join
/**convert_ANY_sublink_to_join:trytoconvertanANYSubLinktoajoin**ThecallerhasfoundanANYSubLinkatthetoplevelofoneofthequery's*qualclauses,buthasnotcheckedthepropertiesoftheSubLinkfurther.*DecidewhetheritisappropriatetoprocessthisSubLinkinjoinstyle.*Ifso,formaJoinExprandreturnit.ReturnNULLiftheSubLinkcannot*beconvertedtoajoin.**Theonlynon-obviousinputparameterisavailable_rels:thisistheset*ofqueryrelsthatcansafelybereferencedinthesublinkexpression.*(Wemustrestrictthistoavoidchangingthesemanticswhenasublink*ispresentinanouterjoin'sONqual.)Theconversionmustfailif*theconvertedqualwouldreferenceanybuttheseparent-queryrelids.**Onsuccess,thereturnedJoinExprhaslarg=NULLandrarg=thejointree*itemrepresentingthepulled-upsubquery.Thecallermustsetlargto*representtherelation(s)onthelefthandsideofthenewjoin,andinsert*theJoinExprintotheupperquery'sjointreeatanappropriateplace*(typically,wherethelefthandrelation(s)hadbeen).Notethatthe*passed-inSubLinkmustalsoberemovedfromitsoriginalpositioninthe*queryquals,sincethequalsofthereturnedJoinExprreplaceit.*(Notionally,wereplacetheSubLinkwithaconstantTRUE,thenelidethe*redundantconstantfromthequal.)**Onsuccess,thecallerisalsoresponsibleforrecursivelyapplying*pull_up_sublinksprocessingtotherargandqualsofthereturnedJoinExpr.*(Onfailure,thereisnoneedtodoanything,sincepull_up_sublinkswill*beappliedwhenwerecursivelyplanthesub-select.)**SideeffectsofasuccessfulconversionincludeaddingtheSubLink's*subselecttothequery'srangetable,sothatitcanbereferencedin*theJoinExpr'srarg.*/JoinExpr*convert_ANY_sublink_to_join(PlannerInfo*root,SubLink*sublink,Relidsavailable_rels){JoinExpr*result;Query*parse=root->parse;Query*subselect=(Query*)sublink->subselect;Relidsupper_varnos;intrtindex;RangeTblEntry*rte;RangeTblRef*rtr;List*subquery_vars;Node*quals;ParseState*pstate;Assert(sublink->subLinkType==ANY_SUBLINK);/**Thesub-selectmustnotrefertoanyVarsoftheparentquery.(Varsof*higherlevelsshouldbeokay,though.)*///ANY类型的子链接,子查询不能依赖父查询的任何变量,否则返回NULL(不能上拉)if(contain_vars_of_level((Node*)subselect,1))returnNULL;/**ThetestexpressionmustcontainsomeVarsoftheparentquery,else*it'snotgonnabeajoin.(Notethatitwon'thaveVarsreferringto*thesubquery,ratherParams.)*///子查询的testexpr变量中必须含有父查询的某些Vars,否则不能上拉(join),返回NULLupper_varnos=pull_varnos(sublink->testexpr);if(bms_is_empty(upper_varnos))returnNULL;/**However,itcan'trefertoanythingoutsideavailable_rels.*///但是不能够依赖超出可用的范围之内,否则一样不能上拉if(!bms_is_subset(upper_varnos,available_rels))returnNULL;/**Thecombiningoperatorsandleft-handexpressionsmustn'tbevolatile.*///组合操作符和左侧的表达式不能是易变(volatile)的,比如随机数等if(contain_volatile_functions(sublink->testexpr))returnNULL;//校验通过,上拉/*CreateadummyParseStateforaddRangeTableEntryForSubquery*/pstate=make_parsestate(NULL);/**Okay,pullupthesub-selectintoupperrangetable.**Werelyhereontheassumptionthattheouterqueryhasnoreferences*totheinner(necessarilytrue,otherthantheVarsthatwebuild*below).Thereforethisisaloteasierthanwhatpull_up_subquerieshas*togothrough.*///子链接上拉后,子查询变成了上层的RTE,在这里构造rte=addRangeTableEntryForSubquery(pstate,subselect,makeAlias("ANY_subquery",NIL),false,false);//添加到上层的rtable中parse->rtable=lappend(parse->rtable,rte);//rtable中的索引rtindex=list_length(parse->rtable);/**FormaRangeTblRefforthepulled-upsub-select.*///产生了RTE,自然要生成RTR(RangeTblRef)rtr=makeNode(RangeTblRef);rtr->rtindex=rtindex;/**BuildalistofVarsrepresentingthesubselectoutputs.*///创建子查询的输出列(投影)subquery_vars=generate_subquery_vars(root,subselect->targetList,rtindex);/**Buildthenewjoin'squalexpression,replacingParamswiththeseVars.*///构造上层的条件表达式quals=convert_testexpr(root,sublink->testexpr,subquery_vars);/**Andfinally,buildtheJoinExprnode.*///构造返回结果result=makeNode(JoinExpr);result->jointype=JOIN_SEMI;//变换为半连接result->isNatural=false;result->larg=NULL;/*callermustfillthisin*/result->rarg=(Node*)rtr;result->usingClause=NIL;result->quals=quals;result->alias=NULL;result->rtindex=0;/*wedon'tneedanRTEforit*/returnresult;}三、数据结构
Param
/**Param**paramkindspecifiesthekindofparameter.Thepossiblevalues*forthisfieldare:**PARAM_EXTERN:Theparametervalueissuppliedfromoutsidetheplan.*Suchparametersarenumberedfrom1ton.**PARAM_EXEC:Theparameterisaninternalexecutorparameter,used*forpassingvaluesintoandoutofsub-queriesorfrom*nestloopjoinstotheirinnerscans.*Forhistoricalreasons,suchparametersarenumberedfrom0.*ThesenumbersareindependentofPARAM_EXTERNnumbers.**PARAM_SUBLINK:TheparameterrepresentsanoutputcolumnofaSubLink*node'ssub-select.Thecolumnnumberiscontainedinthe*`paramid'field.(ThistypeofParamisconvertedto*PARAM_EXECduringplanning.)**PARAM_MULTIEXPR:LikePARAM_SUBLINK,theparameterrepresentsan*outputcolumnofaSubLinknode'ssub-select,buthere,the*SubLinkisalwaysaMULTIEXPRSubLink.Thehigh-order16bits*ofthe`paramid'fieldcontaintheSubLink'ssubLinkId,and*thelow-order16bitscontainthecolumnnumber.(Thistype*ofParamisalsoconvertedtoPARAM_EXECduringplanning.)*/typedefenumParamKind{PARAM_EXTERN,PARAM_EXEC,PARAM_SUBLINK,PARAM_MULTIEXPR}ParamKind;typedefstructParam{Exprxpr;ParamKindparamkind;/*kindofparameter.Seeabove*/intparamid;/*numericIDforparameter*/Oidparamtype;/*pg_typeOIDofparameter'sdatatype*/int32paramtypmod;/*typmodvalue,ifknown*/Oidparamcollid;/*OIDofcollation,orInvalidOidifnone*/intlocation;/*tokenlocation,or-1ifunknown*/}Param;四、跟踪分析
测试脚本:
select*fromt_dwxxawheredwbh>any(selectb.dwbhfromt_grxxb);
gdb跟踪:
(gdb)bpull_up_sublinksBreakpoint1at0x77cbc6:fileprepjointree.c,line157.(gdb)cContinuing.Breakpoint1,pull_up_sublinks(root=0x249f318)atprepjointree.c:157157(Node*)root->parse->jointree,(gdb)#输入参数root->parse是查询树#查询树结构见第2小结中的查询树图...(gdb)p*root->parse$2={type=T_Query,commandType=CMD_SELECT,querySource=QSRC_ORIGINAL,queryId=0,canSetTag=true,utilityStmt=0x0,resultRelation=0,hasAggs=false,hasWindowFuncs=false,hasTargetSRFs=false,hasSubLinks=true,hasDistinctOn=false,hasRecursive=false,hasModifyingCTE=false,hasForUpdate=false,hasRowSecurity=false,cteList=0x0,rtable=0x23b0798,jointree=0x23d3290,targetList=0x23b0bc8,override=OVERRIDING_NOT_SET,onConflict=0x0,returningList=0x0,groupClause=0x0,groupingSets=0x0,havingQual=0x0,windowClause=0x0,distinctClause=0x0,sortClause=0x0,limitOffset=0x0,limitCount=0x0,rowMarks=0x0,setOperations=0x0,constraintDeps=0x0,withCheckOptions=0x0,stmt_location=0,stmt_len=70}(gdb)#第1次进入pull_up_sublinks_jointree_recurse(gdb)n156jtnode=pull_up_sublinks_jointree_recurse(root,(gdb)steppull_up_sublinks_jointree_recurse(root=0x249f318,jtnode=0x23d3290,relids=0x7ffc4fd1ad90)atprepjointree.c:180180if(jtnode==NULL)(gdb)n184elseif(IsA(jtnode,RangeTblRef))(gdb)206newchild=pull_up_sublinks_jointree_recurse(root,(gdb)p*jtnode$3={type=T_FromExpr}(gdb)#第2次调用pull_up_sublinks_jointree_recurse,输入参数的jtnode为RangeTblRef#第2次调用后返回信息(gdb)n209newfromlist=lappend(newfromlist,newchild);(gdb)p*(RangeTblRef*)newchild$8={type=T_RangeTblRef,rtindex=1}...#进入pull_up_sublinks_qual_recurse(gdb)steppull_up_sublinks_qual_recurse(root=0x249f318,node=0x23b00e8,jtlink1=0x7ffc4fd1ad28,available_rels1=0x249fa98,jtlink2=0x0,available_rels2=0x0)atprepjointree.c:335335if(node==NULL)#1.root=PlannerInfo#2.node=f->quals,即SubLink(结构参见查询树图)#3.jtlink1=FromExpr(指针数组)(gdb)p**(FromExpr**)jtlink1$29={type=T_FromExpr,fromlist=0x246e0b8,quals=0x0}...#进入convert_ANY_sublink_to_join(gdb)346if((j=convert_ANY_sublink_to_join(root,sublink,(gdb)#输入参数#1.root见上#2.sublink,子链接#3.available_rels,可用的rels...#sublink中的子查询1322Query*subselect=(Query*)sublink->subselect;(gdb)1337if(contain_vars_of_level((Node*)subselect,1))(gdb)p*subselect$2={type=T_Query,commandType=CMD_SELECT,querySource=QSRC_ORIGINAL,queryId=0,canSetTag=true,utilityStmt=0x0,resultRelation=0,hasAggs=false,hasWindowFuncs=false,hasTargetSRFs=false,hasSubLinks=false,hasDistinctOn=false,hasRecursive=false,hasModifyingCTE=false,hasForUpdate=false,hasRowSecurity=false,cteList=0x0,rtable=0x1cb1030,jointree=0x1cb1240,targetList=0x1cb1210,override=OVERRIDING_NOT_SET,onConflict=0x0,returningList=0x0,groupClause=0x0,groupingSets=0x0,havingQual=0x0,windowClause=0x0,distinctClause=0x0,sortClause=0x0,limitOffset=0x0,limitCount=0x0,rowMarks=0x0,setOperations=0x0,constraintDeps=0x0,withCheckOptions=0x0,stmt_location=0,stmt_len=0}...(gdb)p*upper_varnos.words$4=2(gdb)pavailable_rels$5=(Relids)0x1c8ab68(gdb)p*available_rels$6={nwords=1,words=0x1c8ab6c}(gdb)p*available_rels.words$7=2...#子链接被上拉为上一层jointree的rarg#larg由上层填充1411returnresult;(gdb)p*result$10={type=T_JoinExpr,jointype=JOIN_SEMI,isNatural=false,larg=0x0,rarg=0x1c96e88,usingClause=0x0,quals=0x1c96ef0,alias=0x0,rtindex=0}(gdb)n1412}(gdb)n#回到pull_up_sublinks_qual_recursepull_up_sublinks_qual_recurse(root=0x1c8a3e8,node=0x1bc1038,jtlink1=0x7ffc99e060e8,available_rels1=0x1c8ab68,jtlink2=0x0,available_rels2=0x0)atprepjointree.c:350350j->larg=*jtlink1;(gdb)n351*jtlink1=(Node*)j;#larg为RTF(rtindex=1)(gdb)p*jtlink1$13=(Node*)0x1c96ca8(gdb)p**jtlink1$14={type=T_FromExpr}(gdb)p**(FromExpr**)jtlink1$15={type=T_FromExpr,fromlist=0x1c96c78,quals=0x0}(gdb)p**(FromExpr**)jtlink1->fromlistThereisnomembernamedfromlist.(gdb)p*(*(FromExpr**)jtlink1)->fromlist$16={type=T_List,length=1,head=0x1c96c58,tail=0x1c96c58}(gdb)p*(Node*)(*(FromExpr**)jtlink1)->fromlist->head->data.ptr_value$17={type=T_RangeTblRef}(gdb)p*(RangeTblRef*)(*(FromExpr**)jtlink1)->fromlist->head->data.ptr_value$18={type=T_RangeTblRef,rtindex=1}#递归上拉右树(gdb)steppull_up_sublinks_jointree_recurse(root=0x1c8a3e8,jtnode=0x1c96e88,relids=0x7ffc99e06048)atprepjointree.c:180180if(jtnode==NULL)(gdb)p*jtnode$19={type=T_RangeTblRef}#RTR,退出(gdb)finishRuntillexitfrom#0pull_up_sublinks_jointree_recurse(root=0x1c8a3e8,jtnode=0x1c96e88,relids=0x7ffc99e06048)atprepjointree.c:1800x000000000077d00ainpull_up_sublinks_qual_recurse(root=0x1c8a3e8,node=0x1bc1038,jtlink1=0x7ffc99e060e8,available_rels1=0x1c8ab68,jtlink2=0x0,available_rels2=0x0)atprepjointree.c:353353j->rarg=pull_up_sublinks_jointree_recurse(root,Valuereturnedis$20=(Node*)0x1c96e88(gdb)n362j->quals=pull_up_sublinks_qual_recurse(root,(gdb)step#递归上拉条件表达式,节点类型为OpExpr,无需处理Breakpoint1,pull_up_sublinks_qual_recurse(root=0x1c8a3e8,node=0x1c96ef0,jtlink1=0x1c97100,available_rels1=0x1c8ab68,jtlink2=0x1c97108,available_rels2=0x1c97140)atprepjointree.c:335335if(node==NULL)(gdb)n337if(IsA(node,SubLink))(gdb)p*node$21={type=T_OpExpr}...369returnNULL;(gdb)552}(gdb)#回到pull_up_sublinks_jointree_recursepull_up_sublinks_jointree_recurse(root=0x1c8a3e8,jtnode=0x1cb1540,relids=0x7ffc99e06150)atprepjointree.c:230230*relids=frelids;(gdb)p*newf#newf的条件表达式为NULL(TRUE)$22={type=T_FromExpr,fromlist=0x1c96c78,quals=0x0}(gdb)p*jtlink$23={type=T_JoinExpr}(gdb)n231jtnode=jtlink;(gdb)n312returnjtnode;(gdb)313}(gdb)pull_up_sublinks(root=0x1c8a3e8)atprepjointree.c:164164if(IsA(jtnode,FromExpr))(gdb)167root->parse->jointree=makeFromExpr(list_make1(jtnode),NULL);(gdb)168}(gdb)subquery_planner(glob=0x1bc1d50,parse=0x1bc1328,parent_root=0x0,hasRecursion=false,tuple_fraction=0)atplanner.c:656warning:Sourcefileismorerecentthanexecutable.656inline_set_returning_functions(root);(gdb)finishRuntillexitfrom#0subquery_planner(glob=0x1bc1d50,parse=0x1bc1328,parent_root=0x0,hasRecursion=false,tuple_fraction=0)atplanner.c:6560x0000000000769a49instandard_planner(parse=0x1bc1328,cursorOptions=256,boundParams=0x0)atplanner.c:405405root=subquery_planner(glob,parse,NULL,Valuereturnedis$24=(PlannerInfo*)0x1c8a3e8(gdb)#DONE!
“PostgreSQL查询优化中如何实现上拉子链接”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。