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

set_base_rel_pathlists函数的目的是为每一个base rel找出所有可用的访问路径(包括顺序扫描和所有可用的索引),每一个可用的路径都会添加到pathlist链表中。

一、数据结构

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*///FDW相关信息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;/*是否存在等价类连接?True意味着joininfo并不完整,,Tmeansjoininfoisincomplete*//*usedbypartitionwisejoins:*///是否尝试partitionwise连接,这是PG11的一个新特性.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;

Cost相关
注意:实际使用的参数值通过系统配置文件定义,而不是这里的常量定义!

/**Thecostestimateproducedbycost_qual_eval()includesbothaone-time*(startup)cost,andaper-tuplecost.*/typedefstructQualCost{Coststartup;/*启动成本,one-timecost*/Costper_tuple;/*每个元组的成本,per-evaluationcost*/}QualCost;typedefdoubleCost;/*executioncost(inpage-accessunits)*//*defaultsforcostsize.c'sCostparameters*//*NB:cost-estimationcodeshouldusethevariables,nottheseconstants!*//*注意:实际值通过系统配置文件定义,而不是这里的常量定义!*//*Ifyouchangethese,updatebackend/utils/misc/postgresql.sample.conf*/#defineDEFAULT_SEQ_PAGE_COST1.0//顺序扫描page的成本#defineDEFAULT_RANDOM_PAGE_COST4.0//随机扫描page的成本#defineDEFAULT_CPU_TUPLE_COST0.01//处理一个元组的CPU成本#defineDEFAULT_CPU_INDEX_TUPLE_COST0.005//处理一个索引元组的CPU成本#defineDEFAULT_CPU_OPERATOR_COST0.0025//执行一次操作或函数的CPU成本#defineDEFAULT_PARALLEL_TUPLE_COST0.1//并行执行,从一个worker传输一个元组到另一个worker的成本#defineDEFAULT_PARALLEL_SETUP_COST1000.0//构建并行执行环境的成本#defineDEFAULT_EFFECTIVE_CACHE_SIZE524288/*先前已有介绍,measuredinpages*/doubleseq_page_cost=DEFAULT_SEQ_PAGE_COST;doublerandom_page_cost=DEFAULT_RANDOM_PAGE_COST;doublecpu_tuple_cost=DEFAULT_CPU_TUPLE_COST;doublecpu_index_tuple_cost=DEFAULT_CPU_INDEX_TUPLE_COST;doublecpu_operator_cost=DEFAULT_CPU_OPERATOR_COST;doubleparallel_tuple_cost=DEFAULT_PARALLEL_TUPLE_COST;doubleparallel_setup_cost=DEFAULT_PARALLEL_SETUP_COST;inteffective_cache_size=DEFAULT_EFFECTIVE_CACHE_SIZE;Costdisable_cost=1.0e10;//1后面10个0,通过设置一个巨大的成本,让优化器自动放弃此路径intmax_parallel_workers_per_gather=2;//每次gather使用的worker数

IndexClauseSet
用于收集匹配索引的的条件语句

/*Datastructureforcollectingqualclausesthatmatchanindex*/typedefstruct{boolnonempty;/*Trueiflistsarenotallempty*//*ListsofRestrictInfos,oneperindexcolumn*/List*indexclauses[INDEX_MAX_KEYS];}IndexClauseSet;二、源码解读

set_base_rel_pathlists函数遍历RelOptInfo数组,为每一个Rel构造访问路径,先前已介绍了顺序扫描的成本估算,本节介绍索引扫描的成本估算(函数:create_index_paths),通过调用set_plain_rel_pathlist->create_index_paths函数实现.

/**set_plain_rel_pathlist*Buildaccesspathsforaplainrelation(nosubquery,noinheritance)*/staticvoidset_plain_rel_pathlist(PlannerInfo*root,RelOptInfo*rel,RangeTblEntry*rte){Relidsrequired_outer;//.../*索引扫描,Considerindexscans*/create_index_paths(root,rel);/*TID扫描,ConsiderTIDscans*/create_tidscan_paths(root,rel);}

create_index_paths
create_index_paths函数生成Relation所有可能被选中的索引访问路径,详见源码注释.

/**create_index_paths()*Generateallinterestingindexpathsforthegivenrelation.*Candidatepathsareaddedtotherel'spathlist(usingadd_path).*生成Relation所有可能被选中的索引访问路径.*Paths通过add_path方法加入到RelOptInfo的pathlist链表中.**Tobeconsideredforanindexscan,anindexmustmatchoneormore*restrictionclausesorjoinclausesfromthequery'squalcondition,*ormatchthequery'sORDERBYcondition,orhaveapredicatethat*matchesthequery'squalcondition.*使用索引扫描的前提是:1.索引必须匹配一个或多个限制条件或连接条件,或者*2.匹配查询的ORDERBY排序条件,或者3.匹配查询条件的谓词(部分/条件索引)**Therearetwobasickindsofindexscans.A"plain"indexscanuses*onlyrestrictionclauses(possiblynoneatall)initsindexqual,*soitcanbeappliedinanycontext.A"parameterized"indexscanuses*joinclauses(plusrestrictionclauses,ifavailable)initsindexqual.*Whenjoiningsuchascantooneoftherelationssupplyingtheother*variablesusedinitsindexqual,theparameterizedscanmustappearas*theinnerrelationofanestloopjoin;itcan'tbeusedontheouterside,*norinamergeorhashjoin.Inthatcontext,valuesfortheotherrels'*attributesareavailableandfixedduringanyonescanoftheindexpath.*有两种基本的索引扫描类型,一种是"plain"索引扫描,只使用限制条件(或者什么都*没有),这种扫描方法适用于任何场景.另外一种是"parameterized"扫描,使用连接条件*(可能的话,加上限制条件)."parameterized"扫描只能出现在嵌套循环中的内关系中,*因为参数由外关系提供.**AnIndexPathisgeneratedandsubmittedtoadd_path()foreachplainor*parameterizedindexscanthisroutinedeemspotentiallyinterestingfor*thecurrentquery.*IndexPath访问路径通过函数add_path生成并提交.**输入参数:*'rel'istherelationforwhichwewanttogenerateindexpaths*rel是待生成索引范围路径的关系**Note:check_index_predicates()musthavebeenrunpreviouslyforthisrel.*注意:函数check_index_predicates在调用此函数前调用**Note:incasesinvolvingLATERALreferencesintherelation'stlist,it's*possiblethatrel->lateral_relidsisnonempty.Currently,weinclude*lateral_relidsintotheparameterizationreportedforeachpath,butdon't*takeitintoaccountotherwise.Thefactthatanysuchrels*must*be*availableasparametersourcesperhapsshouldinfluenceourchoicesof*indexquals...butfornow,itdoesn'tseemworthtroublingover.*Inparticular,commentsbelowabout"unparameterized"pathsshouldberead*asmeaning"unparameterizedsofarastheindexqualsareconcerned".*/voidcreate_index_paths(PlannerInfo*root,RelOptInfo*rel){List*indexpaths;//索引访问路径链表List*bitindexpaths;//List*bitjoinpaths;List*joinorclauses;IndexClauseSetrclauseset;IndexClauseSetjclauseset;IndexClauseSeteclauseset;ListCell*lc;/*Skipthewholemessifnoindexes*/if(rel->indexlist==NIL)//不存在索引,退出return;/*Bitmappathsarecollectedandthendealtwithattheend*/bitindexpaths=bitjoinpaths=joinorclauses=NIL;//初始赋值/*Examineeachindexinturn*/foreach(lc,rel->indexlist)//遍历索引链表{IndexOptInfo*index=(IndexOptInfo*)lfirst(lc);//索引信息/*Protectlimited-sizearrayinIndexClauseSets*/Assert(index->ncolumns<=INDEX_MAX_KEYS);/**Ignorepartialindexesthatdonotmatchthequery.*(generate_bitmap_or_paths()mightbeabletodosomethingwith*them,butthat'sofnoconcernhere.)*/if(index->indpred!=NIL&&!index->predOK)//部分索引,而且不能使用,不使用此索引continue;/**Identifytherestrictionclausesthatcanmatchtheindex.*验证索引和条件是否匹配*/MemSet(&rclauseset,0,sizeof(rclauseset));match_restriction_clauses_to_index(rel,index,&rclauseset);/**Buildindexpathsfromtherestrictionclauses.Thesewillbe*non-parameterizedpaths.Plainpathsgodirectlytoadd_path(),*bitmappathsareaddedtobitindexpathstobehandledbelow.*通过限制条件创建非参数化索引访问路径.Plain访问路径通过函数add_path直接添加到RelOptInfo中*位图访问路径添加到bitindexpaths链表中,后续再处理*/get_index_paths(root,rel,index,&rclauseset,&bitindexpaths);/**Identifythejoinclausesthatcanmatchtheindex.Forthemoment*wekeepthemseparatefromtherestrictionclauses.Notethatthis*stepfindsonly"loose"joinclausesthathavenotbeenmergedinto*EquivalenceClasses.Also,collectjoinORclausesforlater.*验证索引是否与连接条件匹配(连接条件与限制条件相互独立).*这一步只是发现未被合并到EC中的"loose"连接条件,在此之后会收集连接中的OR条件*/MemSet(&jclauseset,0,sizeof(jclauseset));match_join_clauses_to_index(root,rel,index,&jclauseset,&joinorclauses);/**LookforEquivalenceClassesthatcangeneratejoinclausesmatching*theindex.*通过EC(等价类)匹配索引,结果存储在eclauseset链表中*/MemSet(&eclauseset,0,sizeof(eclauseset));match_eclass_clauses_to_index(root,index,&eclauseset);/**Ifwefoundanyplainoreclassjoinclauses,buildparameterized*indexpathsusingthem.*如果存在plain或者eclass连接条件,创建参数化索引访问路径*/if(jclauseset.nonempty||eclauseset.nonempty)consider_index_join_clauses(root,rel,index,&rclauseset,&jclauseset,&eclauseset,&bitjoinpaths);}/**GenerateBitmapOrPathsforanysuitableOR-clausespresentinthe*restrictionlist.Addthesetobitindexpaths.*基于RelOptInfo中的限制条件生成BitmapOrPaths访问路径*/indexpaths=generate_bitmap_or_paths(root,rel,rel->baserestrictinfo,NIL);bitindexpaths=list_concat(bitindexpaths,indexpaths);//合并到bitindexpaths链表中/**Likewise,generateBitmapOrPathsforanysuitableOR-clausespresentin*thejoinclauselist.Addthesetobitjoinpaths.*同样的,基于连接条件joinorclause中的OR语句生成BitmapOrPaths访问路径*/indexpaths=generate_bitmap_or_paths(root,rel,joinorclauses,rel->baserestrictinfo);bitjoinpaths=list_concat(bitjoinpaths,indexpaths);//合并到bitjoinpaths链表中/**Ifwefoundanythingusable,generateaBitmapHeapPathforthemost*promisingcombinationofrestrictionbitmapindexpaths.Notethere*willbeonlyonesuchpathnomatterhowmanyindexesexist.This*shouldbesufficientsincethere'sbasicallyonlyonefigureofmerit*(totalcost)forsuchapath.*/if(bitindexpaths!=NIL)//存在位图索引访问路径{Path*bitmapqual;//访问路径BitmapHeapPath*bpath;//BitmapHeapPath访问路径bitmapqual=choose_bitmap_and(root,rel,bitindexpaths);//位图表达式路径bpath=create_bitmap_heap_path(root,rel,bitmapqual,rel->lateral_relids,1.0,0);//BitmapHeapPath访问路径add_path(rel,(Path*)bpath);//添加到RelOptInfo中/*createapartialbitmapheappath*/if(rel->consider_parallel&&rel->lateral_relids==NULL)create_partial_bitmap_paths(root,rel,bitmapqual);//创建并行访问路径}/**Likewise,ifwefoundanythingusable,generateBitmapHeapPathsforthe*mostpromisingcombinationsofjoinbitmapindexpaths.Ourstrategy*istogenerateonesuchpathforeachdistinctparameterizationseen*amongtheavailablebitmapindexpaths.Thismaylookpretty*expensive,butusuallytherewon'tbeverymanydistinct*parameterizations.(Thislogicisquitesimilartothatin*consider_index_join_clauses,butwe'reworkingwithwholepathsnot*individualclauses.)*/if(bitjoinpaths!=NIL)//bitjoinpaths位图连接访问路径{List*path_outer;//依赖的外部Relids链表List*all_path_outers;//依赖的外部路径Relids链表ListCell*lc;//临时变量/**path_outerholdstheparameterizationofeachpathinbitjoinpaths*(tosaverecalculatingthatseveraltimes),whileall_path_outers*holdsalldistinctparameterizationsets.*/path_outer=all_path_outers=NIL;//初始化变量foreach(lc,bitjoinpaths)//遍历bitjoinpaths{Path*path=(Path*)lfirst(lc);//访问路径Relidsrequired_outer;//依赖的外部Relidsrequired_outer=get_bitmap_tree_required_outer(path);//path_outer=lappend(path_outer,required_outer);//添加到链表中if(!bms_equal_any(required_outer,all_path_outers))//不等,则添加到all_path_outers中all_path_outers=lappend(all_path_outers,required_outer);}/*Now,foreachdistinctparameterizationset...*///对每一个唯一的参数化集合进行处理foreach(lc,all_path_outers)//遍历all_path_outers{Relidsmax_outers=(Relids)lfirst(lc);List*this_path_set;Path*bitmapqual;Relidsrequired_outer;doubleloop_count;BitmapHeapPath*bpath;ListCell*lcp;ListCell*lco;/*Identifyallthebitmapjoinpathsneedingnomorethanthat*/this_path_set=NIL;forboth(lcp,bitjoinpaths,lco,path_outer)//遍历{Path*path=(Path*)lfirst(lcp);Relidsp_outers=(Relids)lfirst(lco);if(bms_is_subset(p_outers,max_outers))//无需依赖其他Relids,添加到this_path_set中this_path_set=lappend(this_path_set,path);}/**Addinrestrictionbitmappaths,sincetheycanbeused*togetherwithanyjoinpaths.*/this_path_set=list_concat(this_path_set,bitindexpaths);//合并bitindexpaths访问路径/*SelectbestANDcombinationforthisparameterization*/bitmapqual=choose_bitmap_and(root,rel,this_path_set);//为此参数化处理选择最好的AND组合/*Andpushthatpathintothemix*/required_outer=get_bitmap_tree_required_outer(bitmapqual);loop_count=get_loop_count(root,rel->relid,required_outer);bpath=create_bitmap_heap_path(root,rel,bitmapqual,required_outer,loop_count,0);//创建索引访问路径add_path(rel,(Path*)bpath);}}}

match_XXX
match_restriction_clauses_to_index函数验证限制条件是否与Index匹配,匹配的条件添加到clauseset中.
match_join_clauses_to_index函数验证连接条件是否与Index匹配,同样的,匹配的条件添加到clauseset中.
match_eclass_clauses_to_index函数验证EC连接条件是否与Index匹配,匹配的条件添加到clauseset中.

//---------------------------------------------------match_restriction_clauses_to_index/**match_restriction_clauses_to_index*Identifyrestrictionclausesfortherelthatmatchtheindex.*Matchingclausesareaddedto*clauseset.*验证限制条件是否与Index匹配,匹配的条件加入到clauseset中*/staticvoidmatch_restriction_clauses_to_index(RelOptInfo*rel,IndexOptInfo*index,IndexClauseSet*clauseset){/*Wecanignoreclausesthatareimpliedbytheindexpredicate*///忽略部分(条件)索引,直接调用match_clauses_to_indexmatch_clauses_to_index(index,index->indrestrictinfo,clauseset);}//-------------------------------match_clauses_to_index/**match_clauses_to_index*Performmatch_clause_to_index()foreachclauseinalist.*Matchingclausesareaddedto*clauseset.*/staticvoidmatch_clauses_to_index(IndexOptInfo*index,List*clauses,IndexClauseSet*clauseset){ListCell*lc;//临时变量foreach(lc,clauses)//遍历限制条件{RestrictInfo*rinfo=lfirst_node(RestrictInfo,lc);match_clause_to_index(index,rinfo,clauseset);}}//---------------------------------------------------match_join_clauses_to_index/**match_join_clauses_to_index*Identifyjoinclausesfortherelthatmatchtheindex.*Matchingclausesareaddedto*clauseset.*Also,addanypotentiallyusablejoinORclausesto*joinorclauses.*验证连接条件是否与Index匹配,匹配的条件添加到clauseset中*另外,在joinorclauses中添加可能有用的连接条件OR子句*/staticvoidmatch_join_clauses_to_index(PlannerInfo*root,RelOptInfo*rel,IndexOptInfo*index,IndexClauseSet*clauseset,List**joinorclauses){ListCell*lc;//临时变量/*Scantherel'sjoinclauses*/foreach(lc,rel->joininfo)//遍历连接条件{RestrictInfo*rinfo=(RestrictInfo*)lfirst(lc);/*Checkifclausecanbemovedtothisrel*/if(!join_clause_is_movable_to(rinfo,rel))continue;/*Potentiallyusable,soseeifitmatchestheindexorisanOR*/if(restriction_is_or_clause(rinfo))*joinorclauses=lappend(*joinorclauses,rinfo);elsematch_clause_to_index(index,rinfo,clauseset);}}//---------------------------------------------------match_eclass_clauses_to_index/**match_eclass_clauses_to_index*IdentifyEquivalenceClassjoinclausesfortherelthatmatchtheindex.*Matchingclausesareaddedto*clauseset.*验证EC连接条件是否与Index匹配,相匹配的子句加入到clauseset中*/staticvoidmatch_eclass_clauses_to_index(PlannerInfo*root,IndexOptInfo*index,IndexClauseSet*clauseset){intindexcol;/*NoworkifrelisnotinanysuchECs*/if(!index->rel->has_eclass_joins)//没有ECs,返回return;for(indexcol=0;indexcol<index->nkeycolumns;indexcol++)//遍历索引列{ec_member_matches_argarg;List*clauses;/*Generateclauses,skippinganythatjointolateral_referencers*///生成条件子句链表arg.index=index;arg.indexcol=indexcol;clauses=generate_implied_equalities_for_column(root,index->rel,ec_member_matches_indexcol,(void*)&arg,index->rel->lateral_referencers);/**Wehavetocheckwhethertheresultsactuallydomatchtheindex,*sincefornon-btreeindexestheEC'sequalityoperatorsmightnot*beintheindexopclass(cfec_member_matches_indexcol).*/match_clauses_to_index(index,clauses,clauseset);}}//----------------------------generate_implied_equalities_for_column/**generate_implied_equalities_for_column*CreateEC-derivedjoinclausesusablewithaspecificcolumn.*创建可用于特定列的EC衍生连接条件**Thisisusedbyindxpath.ctoextractpotentiallyindexablejoinclauses*fromECs,andcanbeusedbyforeigndatawrappersforsimilarpurposes.*WeassumethatonlyexpressionsinVarsofasingletableareofinterest,*butthecallerprovidesacallbackfunctiontoidentifyexactlywhich*suchexpressionsitwouldliketoknowabout.**Weassumethatanygiventable/indexcolumncouldappearinonlyoneEC.*(Thisshouldbetrueinallbutthemostpathologicalcases,andifit*isn't,westoponthefirstmatchanyway.)Therefore,whatwereturn*isaredundantlistofclausesequatingthetable/indexcolumntoeachof*theother-relationvaluesitisknowntobeequalto.Anyoneof*theseclausescanbeusedtocreateaparameterizedpath,andthere*isnovalueinusingmorethanone.(Butit*is*worthwhiletocreate*aseparateparameterizedpathforeachone,sincethatleadstodifferent*joinorders.)**ThecallercanpassaRelidssetofrelswearen'tinterestedinjoining*to,soastosavetheworkofcreatinguselessclauses.*/List*generate_implied_equalities_for_column(PlannerInfo*root,RelOptInfo*rel,ec_matches_callback_typecallback,void*callback_arg,Relidsprohibited_rels){List*result=NIL;//结果链表boolis_child_rel=(rel->reloptkind==RELOPT_OTHER_MEMBER_REL);//是否子RelationRelidsparent_relids;//父RelidsListCell*lc1;//变量/*Indexesareavailableonlyonbaseor"other"memberrelations.*/Assert(IS_SIMPLE_REL(rel));/*Ifit'sachildrel,we'llneedtoknowwhatitsparent(s)are*/if(is_child_rel)parent_relids=find_childrel_parents(root,rel);elseparent_relids=NULL;/*notused,butkeepcompilerquiet*/foreach(lc1,root->eq_classes)//遍历EC{EquivalenceClass*cur_ec=(EquivalenceClass*)lfirst(lc1);//当前的ECEquivalenceMember*cur_em;//EC成员ListCell*lc2;//链表成员/**Won'tgeneratejoinclausesifconstorsingle-member(thelatter*testcoversthevolatilecasetoo)*/if(cur_ec->ec_has_const||list_length(cur_ec->ec_members)<=1)continue;/**Nopointinsearchingifrelnotmentionedineclass(butwecan't*tellthatforachildrel).*/if(!is_child_rel&&!bms_is_subset(rel->relids,cur_ec->ec_relids))continue;/**Scanmembers,lookingforamatchtothetargetcolumn.Notethat*childECmembersareconsidered,butonlywhentheybelongtothe*targetrelation.(Unlikeregularmembers,thesameexpression*couldbeachildmemberofmorethanoneEC.Therefore,it's*potentiallyorder-dependentwhichECachildrelation'starget*columngetsmatchedto.Thisisannoyingbutitonlyhappensin*cornercases,sofornowwelivewithjustreportingthefirst*match.Seealsoget_eclass_for_sort_expr.)*/cur_em=NULL;foreach(lc2,cur_ec->ec_members)//遍历EC的成员{cur_em=(EquivalenceMember*)lfirst(lc2);//当前成员if(bms_equal(cur_em->em_relids,rel->relids)&&callback(root,rel,cur_ec,cur_em,callback_arg))//调用ec_member_matches_indexcol函数break;//找到匹配的成员,跳出cur_em=NULL;}if(!cur_em)continue;/**Foundourmatch.ScantheotherECmembersandattempttogenerate*joinclauses.*/foreach(lc2,cur_ec->ec_members){EquivalenceMember*other_em=(EquivalenceMember*)lfirst(lc2);Oideq_op;RestrictInfo*rinfo;if(other_em->em_is_child)//continue;/*忽略子成员,ignorechildrenhere*//*Makesureit'llbeajointoadifferentrel*/if(other_em==cur_em||bms_overlap(other_em->em_relids,rel->relids))//过滤cur_emcontinue;/*Forgetitifcallerdoesn'twantjoinstothisrel*/if(bms_overlap(other_em->em_relids,prohibited_rels))continue;/**Also,ifthisisachildrel,avoidgeneratingauselessjoin*toitsparentrel(s).*/if(is_child_rel&&bms_overlap(parent_relids,other_em->em_relids))continue;eq_op=select_equality_operator(cur_ec,cur_em->em_datatype,other_em->em_datatype);if(!OidIsValid(eq_op))continue;/*setparent_ectomarkasredundantwithotherjoinclauses*/rinfo=create_join_clause(root,cur_ec,eq_op,cur_em,other_em,cur_ec);//创建连接条件语句result=lappend(result,rinfo);}/**Ifsomehowwefailedtocreateanyjoinclauses,wemightaswell*keepscanningtheECsforanothermatch.Butifwedidmakeany,*we'redone,becausewedon'twanttoreturnnon-redundantclauses.*/if(result)break;}returnresult;}//----------------------------match_clause_to_index/**match_clause_to_index*Testwhetheraqualclausecanbeusedwithanindex.**Iftheclauseisusable,addittotheappropriatelistin*clauseset.**clausesetmustbeinitializedtozeroesbeforefirstcall.**Note:insomecircumstanceswemayfindthesameRestrictInfoscomingfrom*multipleplaces.Defendagainstredundantoutputsbyrefusingtoadda*clausetwice(pointerequalityshouldbeagoodenoughcheckforthis).**Note:it'spossiblethatabadly-definedindexcouldhavemultiplematching*columns.Wealwaysselectthefirstmatchifso;thisavoidsscenarios*whereinwegetaninflatedideaoftheindex'sselectivitybyusingthe*sameclausemultipletimeswithdifferentindexcolumns.*/staticvoidmatch_clause_to_index(IndexOptInfo*index,RestrictInfo*rinfo,IndexClauseSet*clauseset){intindexcol;/**Nevermatchpseudoconstantstoindexes.(Normallyamatchcouldnot*happenanyway,sinceapseudoconstantclausecouldn'tcontainaVar,*butwhatifsomeonebuildsanexpressionindexonaconstant?It'snot*totallyunreasonabletodosowithapartialindex,either.)*/if(rinfo->pseudoconstant)return;/**Ifclausecan'tbeusedasanindexqualbecauseitmustwaittillafter*somelower-security-levelrestrictionclause,rejectit.*/if(!restriction_is_securely_promotable(rinfo,index->rel))return;/*OK,checkeachindexkeycolumnforamatch*/for(indexcol=0;indexcol<index->nkeycolumns;indexcol++){if(match_clause_to_indexcol(index,indexcol,rinfo)){clauseset->indexclauses[indexcol]=list_append_unique_ptr(clauseset->indexclauses[indexcol],rinfo);//赋值clauseset->nonempty=true;//设置标记return;}}}//-------------------match_clause_to_indexcol/**match_clause_to_indexcol()*Determineswhetherarestrictionclausematchesacolumnofanindex.*判断约束条件是否与索引中的某一列匹配**Tomatchanindexnormally,theclause:*通常来说,匹配索引,子句必须:*(1)mustbeintheform(indexkeyopconst)or(constopindexkey);*and*满足格式:(索引键操作符常量)或者(常量操作符索引键),而且*(2)mustcontainanoperatorwhichisinthesamefamilyastheindex*operatorforthiscolumn,orisa"special"operatorasrecognized*bymatch_special_index_operator();*and*包含一种与索引列同一family的操作符,或者是一种通过match_special_index_operator方法认定的特殊操作符*(3)mustmatchthecollationoftheindex,ifcollationisrelevant.*与索引的排序规则collation匹配**Ourdefinitionof"const"isexceedinglyliberal:weallowanythingthat*doesn'tinvolveavolatilefunctionoraVaroftheindex'srelation.*Inparticular,Varsbelongingtootherrelationsofthequeryare*acceptedhere,sinceaclauseofthatformcanbeusedina*parameterizedindexscan.It'stheresponsibilityofhighercodelevels*tomanagerestrictionandjoinclausesappropriately.*这里"const"常量的定义非常自由:除了易变函数或索引关系的Var之外的,均视为"const"*由于存在参数化索引扫描的可能,因此查询中属于其他Relations的Vars也可以在此出现.*调用此函数的代码有责任"合适"的管理限制条件和连接条件.**Note:wedoneedtocheckforVarsoftheindex'srelationonthe*"const"sideoftheclause,sinceclauseslike(a.f1OP(b.f2OPa.f3))*arenotprocessablebyaparameterizedindexscanona.f1,whereas*somethinglike(a.f1OP(b.f2OPc.f3))is.*注意:需要在子句的const部分检查索引关系的Vars,因为子句*如(a.f1OP(b.f2OPa.f3)不能通过a上的参数化索引扫描进行处理**Presently,theexecutorcanonlydealwithindexqualsthathavethe*indexkeyontheleft,sowecanonlyuseclausesthathavetheindexkey*ontherightifwecancommutetheclausetoputthekeyontheleft.*Wedonotactuallydothecommutinghere,butwecheckwhethera*suitablecommutatoroperatorisavailable.*目前为止,执行器只能处理索引键在左边的索引表达式,因此只能使用那些可以*把索引键变换到左边的条件表达式.在这个函数中不执行变换,但会执行相应的检查.**Iftheindexhasacollation,theclausemusthavethesamecollation.*Forcollation-lessindexes,weassumeitdoesn'tmatter;thisis*necessaryforcaseslike"hstore?text",whereinhstore'soperators*don'tcareaboutcollationbuttheclausewillgetmarkedwitha*collationanywaybecauseofthetextargument.(Thislogicis*embodiedinthemacroIndexCollMatchesExprColl.)*如果索引含有排序规则(collation),条件子句必须包含相同的排序规则.*对于无collation的索引,假定collation没有任何影响.**ItisalsopossibletomatchRowCompareExprclausestoindexes(but*currently,onlybtreeindexeshandlethis).Inthisroutinewewill*reportamatchifthefirstcolumnoftherowcomparisonmatchesthe*targetindexcolumn.Thisissufficienttoguaranteethatsomeindex*conditioncanbeconstructedfromtheRowCompareExpr---whetherthe*remainingcolumnsmatchtheindextooisconsideredin*adjust_rowcompare_for_index().*RowCompareExpr有可能与索引进行匹配,在这个处理过程中,如果行对比的第一个列*与目标索引匹配,那么可以认为是匹配的.**ItisalsopossibletomatchScalarArrayOpExprclausestoindexes,when*theclauseisoftheform"indexkeyopANY(arrayconst)".*如果子句的格式是"indexkeyopANY(arrayconst)",那么匹配ScalarArrayOpExpr*也是可能的.**Forbooleanindexes,itisalsopossibletomatchtheclausedirectly*totheindexkey;orperhapstheclauseis(NOTindexkey).*对于布尔索引,可以直接与索引键进行匹配**输入参数:*'index'istheindexofinterest.*index-正在处理的索引*'indexcol'isacolumnnumberof'index'(countingfrom0).*indexcol-索引列(从0起算)*'rinfo'istheclausetobetested(asaRestrictInfonode).*rinfo-RestrictInfoNode**Returnstrueiftheclausecanbeusedwiththisindexkey.*如可以使用索引,则返回T**NOTE:returnsfalseifclauseisanORorANDclause;itisthe*responsibilityofhigher-levelroutinestocopewiththose.*注意:如果条件语句是OR/AND语句,则返回F,由上层处理逻辑处理*/staticboolmatch_clause_to_indexcol(IndexOptInfo*index,intindexcol,RestrictInfo*rinfo){Expr*clause=rinfo->clause;//条件语句Indexindex_relid=index->rel->relid;//Index的RelidOidopfamily;//操作符种类Oididxcollation;//索引排序规则Node*leftop,//左节点*rightop;//右节点Relidsleft_relids;//左节点相关RelidsRelidsright_relids;//右节点相关RelidsOidexpr_op;//表达式操作符的OidOidexpr_coll;//表达式Collation的Oidboolplain_op;//是否Plain操作符Assert(indexcol<index->nkeycolumns);opfamily=index->opfamily[indexcol];//获取操作符种类idxcollation=index->indexcollations[indexcol];//获取索引排序规则/*Firstcheckforboolean-indexcases.*/if(IsBooleanOpfamily(opfamily))//是否布尔类{if(match_boolean_index_clause((Node*)clause,indexcol,index))//是否匹配returntrue;//如匹配,返回T}/**Clausemustbeabinaryopclause,orpossiblyaScalarArrayOpExpr*(whichisalwaysbinary,bydefinition).Oritcouldbea*RowCompareExpr,whichwepassofftomatch_rowcompare_to_indexcol().*Or,iftheindexsupportsit,wecanhandleISNULL/NOTNULLclauses.*/if(is_opclause(clause))//OpExpr{leftop=get_leftop(clause);rightop=get_rightop(clause);if(!leftop||!rightop)returnfalse;left_relids=rinfo->left_relids;right_relids=rinfo->right_relids;expr_op=((OpExpr*)clause)->opno;expr_coll=((OpExpr*)clause)->inputcollid;plain_op=true;}elseif(clause&&IsA(clause,ScalarArrayOpExpr))//ScalarArrayOpExpr{ScalarArrayOpExpr*saop=(ScalarArrayOpExpr*)clause;/*WeonlyacceptANYclauses,notALL*/if(!saop->useOr)returnfalse;leftop=(Node*)linitial(saop->args);rightop=(Node*)lsecond(saop->args);left_relids=NULL;/*notactuallyneeded*/right_relids=pull_varnos(rightop);expr_op=saop->opno;expr_coll=saop->inputcollid;plain_op=false;}elseif(clause&&IsA(clause,RowCompareExpr))//RowCompareExpr{returnmatch_rowcompare_to_indexcol(index,indexcol,opfamily,idxcollation,(RowCompareExpr*)clause);}elseif(index->amsearchnulls&&IsA(clause,NullTest))//NullTest{NullTest*nt=(NullTest*)clause;if(!nt->argisrow&&match_index_to_operand((Node*)nt->arg,indexcol,index))returntrue;returnfalse;}elsereturnfalse;/**Checkforclausesoftheform:(indexkeyoperatorconstant)or*(constantoperatorindexkey).Seeabovenotesaboutconst-ness.*(indexkeyoperatorconstant)和(constantoperatorindexkey)格式的语句*///处理:(indexkeyoperatorconstant)if(match_index_to_operand(leftop,indexcol,index)&&!bms_is_member(index_relid,right_relids)&&!contain_volatile_functions(rightop)){if(IndexCollMatchesExprColl(idxcollation,expr_coll)&&is_indexable_operator(expr_op,opfamily,true))//排序规则&操作符种类匹配returntrue;//返回T/**Ifwedidn'tfindamemberoftheindex'sopfamily,seewhetherit*isa"special"indexableoperator.*/if(plain_op&&match_special_index_operator(clause,opfamily,idxcollation,true))//Plain操作&特殊操作符,返回Treturntrue;returnfalse;//否则,返回F}//处理(constantoperatorindexkey)if(plain_op&&match_index_to_operand(rightop,indexcol,index)&&!bms_is_member(index_relid,left_relids)&&!contain_volatile_functions(leftop)){if(IndexCollMatchesExprColl(idxcollation,expr_coll)&&is_indexable_operator(expr_op,opfamily,false))returntrue;/**Ifwedidn'tfindamemberoftheindex'sopfamily,seewhetherit*isa"special"indexableoperator.*/if(match_special_index_operator(clause,opfamily,idxcollation,false))returntrue;returnfalse;}returnfalse;}三、跟踪分析

测试脚本如下

selecta.*,b.grbh,b.jefromt_dwxxa,lateral(selectt1.dwbh,t1.grbh,t2.jefromt_grxxt1innerjoint_jfxxt2ont1.dwbh=a.dwbhandt1.grbh=t2.grbh)bwherea.dwbh='1001'orderbyb.dwbh;

注意:按先前的分析,SQL语句存在等价类{t_dwxx.dwbh t_grxx.dwbh '1001'}和{t_grxx.grbh t_jfxx.grbh},在构造t_grxx的索引访问路径时,使用等价类构造.

启动gdb,第一个RelOptInfo(对应t_dwxx)有3个Index,第二个RelOptInfo(对应t_grxx)有2个Index(分别是在dwbh和grbh上的索引),第三个RelOptInfo(对应t_jfxx)有1个Index(grbh上的索引),本节以t_jfxx和t_grxx为例进行跟踪分析

...(gdb)cContinuing.Breakpoint1,create_index_paths(root=0x2714c50,rel=0x2729530)atindxpath.c:242242if(rel->indexlist==NIL)(gdb)p*(IndexOptInfo*)rel->indexlist->head->data.ptr_value$38={type=T_IndexOptInfo,indexoid=16750,reltablespace=0,rel=0x2729530,pages=276,tuples=100000,tree_height=1,ncolumns=1,nkeycolumns=1,indexkeys=0x2729998,indexcollations=0x27299b0,opfamily=0x27299c8,opcintype=0x27299e0,sortopfamily=0x27299c8,reverse_sort=0x2729a10,nulls_first=0x2729a28,canreturn=0x27299f8,relam=403,indexprs=0x0,indpred=0x0,indextlist=0x2729ae0,indrestrictinfo=0x0,predOK=false,unique=false,immediate=true,hypothetical=false,amcanorderbyop=false,amoptionalkey=true,amsearcharray=true,amsearchnulls=true,amhasgettuple=true,amhasgetbitmap=true,amcanparallel=true,amcostestimate=0x94f0ad<btcostestimate>}

输入信息是已熟知的root(PlannerInfo)和rel(RelOptInfo).首先进行索引遍历循环

(gdb)cContinuing.Breakpoint1,create_index_paths(root=0x2714c50,rel=0x2729530)atindxpath.c:242242if(rel->indexlist==NIL)(gdb)p*(IndexOptInfo*)rel->indexlist->head->data.ptr_value$38={type=T_IndexOptInfo,indexoid=16750,reltablespace=0,rel=0x2729530,pages=276,tuples=100000,tree_height=1,ncolumns=1,nkeycolumns=1,indexkeys=0x2729998,indexcollations=0x27299b0,opfamily=0x27299c8,opcintype=0x27299e0,sortopfamily=0x27299c8,reverse_sort=0x2729a10,nulls_first=0x2729a28,canreturn=0x27299f8,relam=403,indexprs=0x0,indpred=0x0,indextlist=0x2729ae0,indrestrictinfo=0x0,predOK=false,unique=false,immediate=true,hypothetical=false,amcanorderbyop=false,amoptionalkey=true,amsearcharray=true,amsearchnulls=true,amhasgettuple=true,amhasgetbitmap=true,amcanparallel=true,amcostestimate=0x94f0ad<btcostestimate>}

查询数据字典pg_class,oid=16750相应的索引是idx_t_jfxx_grbh

testdb=#selectrelnamefrompg_classwhereoid=16750;relname-----------------idx_t_jfxx_grbh(1row)

调用match_restriction_clauses_to_index和match_join_clauses_to_index,子句集合均为NULL

(gdb)match_restriction_clauses_to_index(rel=0x2729530,index=0x2729888,clauseset=0x7fff69cf0890)atindxpath.c:21172117}(gdb)create_index_paths(root=0x2714c50,rel=0x2729530)atindxpath.c:275275get_index_paths(root,rel,index,&rclauseset,(gdb)284MemSet(&jclauseset,0,sizeof(jclauseset));(gdb)285match_join_clauses_to_index(root,rel,index,(gdb)292MemSet(&eclauseset,0,sizeof(eclauseset));(gdb)293match_eclass_clauses_to_index(root,index,(gdb)prclauseset$2={nonempty=false,indexclauses={0x0<repeats32times>}}(gdb)pjoinorclauses$3=(List*)0x0(gdb)pjclauseset$4={nonempty=false,indexclauses={0x0<repeats32times>}}

进入match_eclass_clauses_to_index

...268match_restriction_clauses_to_index(rel,index,&rclauseset);(gdb)stepmatch_restriction_clauses_to_index(rel=0x2724c88,index=0x27254d8,clauseset=0x7fff69cf0890)atindxpath.c:21162116match_clauses_to_index(index,index->indrestrictinfo,clauseset);

进入generate_implied_equalities_for_column

...(gdb)stepgenerate_implied_equalities_for_column(root=0x2714c50,rel=0x2729530,callback=0x7509b0<ec_member_matches_indexcol>,callback_arg=0x7fff69cf0620,prohibited_rels=0x0)atequivclass.c:22192219List*result=NIL;

等价类信息

...2235EquivalenceClass*cur_ec=(EquivalenceClass*)lfirst(lc1);(gdb)2243if(cur_ec->ec_has_const||list_length(cur_ec->ec_members)<=1)(gdb)p*cur_ec$6={type=T_EquivalenceClass,ec_opfamilies=0x272a268,ec_collation=100,ec_members=0x272a4a8,ec_sources=0x272a3f0,ec_derives=0x272d2f0,ec_relids=0x272a470,ec_has_const=false,ec_has_volatile=false,ec_below_outer_join=false,ec_broken=false,ec_sortref=0,ec_min_security=0,ec_max_security=0,ec_merged=0x0}

遍历EC的成员后,cur_em不为NULL,查看cur_em内存结构(匹配的成员,即t_jfxx.grbh)

2281foreach(lc2,cur_ec->ec_members)(gdb)p*cur_em$7={type=T_EquivalenceMember,em_expr=0x2722890,em_relids=0x272a238,em_nullable_relids=0x0,em_is_const=false,em_is_child=false,em_datatype=25}(gdb)p*cur_em->em_expr$8={type=T_RelabelType}(gdb)p*(RelabelType*)cur_em->em_expr$9={xpr={type=T_RelabelType},arg=0x2722840,resulttype=25,resulttypmod=-1,resultcollid=100,relabelformat=COERCE_IMPLICIT_CAST,location=-1}(gdb)p*((RelabelType*)cur_em->em_expr)->arg$10={type=T_Var}(gdb)p*(Var*)((RelabelType*)cur_em->em_expr)->arg$11={xpr={type=T_Var},varno=4,varattno=1,vartype=1043,vartypmod=14,varcollid=100,varlevelsup=0,varnoold=4,varoattno=1,location=168}

再次遍历等价类的成员,得到第一个约束条件(t_jfxx.grbh=t_grxx.grbh)

(gdb)n2314rinfo=create_join_clause(root,cur_ec,eq_op,(gdb)2318result=lappend(result,rinfo);(gdb)p*rinfo$18={type=T_RestrictInfo,clause=0x272d910,is_pushed_down=true,outerjoin_delayed=false,can_join=true,pseudoconstant=false,leakproof=false,security_level=0,clause_relids=0x272db10,required_relids=0x272d5f0,outer_relids=0x0,nullable_relids=0x0,left_relids=0x272dae0,right_relids=0x272daf8,orclause=0x0,parent_ec=0x272a340,eval_cost={startup=0,per_tuple=0.0025000000000000001},norm_selec=-1,outer_selec=-1,mergeopfamilies=0x272db48,left_ec=0x272a340,right_ec=0x272a340,left_em=0x272a4d8,right_em=0x272a420,scansel_cache=0x0,outer_is_left=false,hashjoinoperator=98,left_bucketsize=-1,right_bucketsize=-1,left_mcvfreq=-1,right_mcvfreq=-1}(gdb)set$tmp1=(RelabelType*)((OpExpr*)rinfo->clause)->args->head->data.ptr_value(gdb)set$tmp2=(RelabelType*)((OpExpr*)rinfo->clause)->args->head->next->data.ptr_value(gdb)p*(Var*)$tmp1->arg$31={xpr={type=T_Var},varno=4,varattno=1,vartype=1043,vartypmod=14,varcollid=100,varlevelsup=0,varnoold=4,varoattno=1,location=168}(gdb)p*(Var*)$tmp2->arg$32={xpr={type=T_Var},varno=3,varattno=2,vartype=1043,vartypmod=14,varcollid=100,varlevelsup=0,varnoold=3,varoattno=2,location=158}

获得了结果,返回到match_eclass_clauses_to_index

2281foreach(lc2,cur_ec->ec_members)(gdb)2326if(result)(gdb)2327break;(gdb)2330returnresult;(gdb)2331}(gdb)match_eclass_clauses_to_index(root=0x2714c50,index=0x2729888,clauseset=0x7fff69cf0670)atindxpath.c:21842184match_clauses_to_index(index,clauses,clauseset);...

下面再考察t_grxx.dwbh上的索引为例,分析match_clause_to_index

(gdb)cContinuing.Breakpoint1,create_index_paths(root=0x2714c50,rel=0x2728c38)atindxpath.c:242242if(rel->indexlist==NIL)(gdb)p*(IndexOptInfo*)rel->indexlist->head->data.ptr_value$39={type=T_IndexOptInfo,indexoid=16752,reltablespace=0,rel=0x2728c38,pages=276,tuples=100000,tree_height=1,ncolumns=1,nkeycolumns=1,indexkeys=0x2729378,indexcollations=0x2729390,opfamily=0x27293a8,opcintype=0x27293c0,sortopfamily=0x27293a8,reverse_sort=0x27293f0,nulls_first=0x2729408,canreturn=0x27293d8,relam=403,indexprs=0x0,indpred=0x0,indextlist=0x27294e0,indrestrictinfo=0x272b040,predOK=false,unique=false,immediate=true,hypothetical=false,amcanorderbyop=false,amoptionalkey=true,amsearcharray=true,amsearchnulls=true,amhasgettuple=true,amhasgetbitmap=true,amcanparallel=true,amcostestimate=0x94f0ad<btcostestimate>}

oid=16752,对应的object为idx_t_grxx_dwbh

testdb=#selectrelnamefrompg_classwhereoid=16752;relname-----------------idx_t_grxx_dwbh(1row)

进入IndexOptInfo循环,第一个元素对应的IndexOptInfo为idx_t_grxx_dwbh

249foreach(lc,rel->indexlist)(gdb)p*rel->indexlist$40={type=T_List,length=2,head=0x2729510,tail=0x2729218}(gdb)p*(IndexOptInfo*)rel->indexlist->head->data->ptr_value$42={type=T_IndexOptInfo,indexoid=16752,reltablespace=0,rel=0x2728c38,pages=276,tuples=100000,tree_height=1,ncolumns=1,nkeycolumns=1,indexkeys=0x2729378,indexcollations=0x2729390,opfamily=0x27293a8,opcintype=0x27293c0,sortopfamily=0x27293a8,reverse_sort=0x27293f0,nulls_first=0x2729408,canreturn=0x27293d8,relam=403,indexprs=0x0,indpred=0x0,indextlist=0x27294e0,indrestrictinfo=0x272b040,predOK=false,unique=false,immediate=true,hypothetical=false,amcanorderbyop=false,amoptionalkey=true,amsearcharray=true,amsearchnulls=true,amhasgettuple=true,amhasgetbitmap=true,amcanparallel=true,amcostestimate=0x94f0ad<btcostestimate>}

一路小跑,进入match_clause_to_indexcol

...(gdb)stepmatch_clause_to_indexcol(index=0x2729268,indexcol=0,rinfo=0x272ae58)atindxpath.c:23302330Expr*clause=rinfo->clause;(gdb)n2331Indexindex_relid=index->rel->relid;(gdb)n2344opfamily=index->opfamily[indexcol];(gdb)2345idxcollation=index->indexcollations[indexcol];(gdb)pindex_relid$47=3(gdb)popfamily$48=1994(gdb)

根据opfamily查询数据字典

testdb=#select*frompg_opfamilywhereoid=1994;opfmethod|opfname|opfnamespace|opfowner-----------+----------+--------------+----------403|text_ops|11|10(1row)--索引访问方法(btree)testdb=#select*frompg_amwhereoid=403;amname|amhandler|amtype--------+-----------+--------btree|bthandler|i(1row)

下面进入is_opclause判断分支

(gdb)pidxcollation$49=100(gdb)n2360if(is_opclause(clause))(gdb)2362leftop=get_leftop(clause);(gdb)2363rightop=get_rightop(clause);(gdb)2364if(!leftop||!rightop)(gdb)p*leftop$50={type=T_RelabelType}(gdb)p*rightop$51={type=T_Const}

限制条件下推后,形成限制条件t_grxx.dwbh = '1001'

#Var:t_grxx.dwbh(gdb)p*(RelabelType*)leftop$56={xpr={type=T_RelabelType},arg=0x272ad80,resulttype=25,resulttypmod=-1,resultcollid=100,relabelformat=COERCE_IMPLICIT_CAST,location=-1}#常量:'1001'(gdb)p*(Const*)rightop$57={xpr={type=T_Const},consttype=25,consttypmod=-1,constcollid=100,constlen=-1,constvalue=41069848,constisnull=false,constbyval=false,location=194}

执行相关判断,返回T

(gdb)n2366left_relids=rinfo->left_relids;(gdb)2367right_relids=rinfo->right_relids;(gdb)2368expr_op=((OpExpr*)clause)->opno;(gdb)2369expr_coll=((OpExpr*)clause)->inputcollid;(gdb)2370plain_op=true;(gdb)2409if(match_index_to_operand(leftop,indexcol,index)&&(gdb)2410!bms_is_member(index_relid,right_relids)&&(gdb)2409if(match_index_to_operand(leftop,indexcol,index)&&(gdb)2411!contain_volatile_functions(rightop))(gdb)2410!bms_is_member(index_relid,right_relids)&&(gdb)2413if(IndexCollMatchesExprColl(idxcollation,expr_coll)&&(gdb)2414is_indexable_operator(expr_op,opfamily,true))(gdb)2413if(IndexCollMatchesExprColl(idxcollation,expr_coll)&&(gdb)2415returntrue;

给clauseset变量赋值

(gdb)match_clause_to_index(index=0x2729268,rinfo=0x272ae58,clauseset=0x7fff69cf0890)atindxpath.c:22552255list_append_unique_ptr(clauseset->indexclauses[indexcol],(gdb)2254clauseset->indexclauses[indexcol]=(gdb)2257clauseset->nonempty=true;(gdb)2258return;(gdb)2261}

返回到match_clauses_to_index

(gdb)match_clauses_to_index(index=0x2729268,clauses=0x272b040,clauseset=0x7fff69cf0890)atindxpath.c:22002200foreach(lc,clauses)

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