PostgreSQL 源碼解讀(99)- 分區(qū)表#5(數(shù)據(jù)查詢(xún)路由#2-RelOptInfo數(shù)據(jù)結(jié)構(gòu))

上一章節(jié)已介紹了如何識(shí)別分區(qū)表并找到所有的分區(qū)子表以及函數(shù)expand_inherited_tables的主要實(shí)現(xiàn)邏輯,該函數(shù)把子表信息放在root(PlannerInfo)->append_rel_list鏈表中就缆。為了更好的理解相關(guān)的邏輯,本節(jié)重點(diǎn)介紹分區(qū)表查詢(xún)相關(guān)的重要數(shù)據(jù)結(jié)構(gòu),包括RelOptInfo/PlannerInfo/AppendRelInfo.

一瓣铣、數(shù)據(jù)結(jié)構(gòu)

RelOptInfo
RelOptInfo是規(guī)劃器/優(yōu)化器使用的關(guān)系信息結(jié)構(gòu)體
在規(guī)劃過(guò)程中已存在的基表或者是在關(guān)系運(yùn)算過(guò)程中產(chǎn)生的中間關(guān)系或者是最終產(chǎn)生的關(guān)系,都使用RelOptInfo結(jié)構(gòu)體進(jìn)行封裝表示.
查詢(xún)分區(qū)表時(shí)該結(jié)構(gòu)體中的part_scheme存儲(chǔ)分區(qū)的schema,nparts存儲(chǔ)分區(qū)數(shù),boundinfo是分區(qū)邊界信息,partition_qual是分區(qū)約束條件,part_rels是分區(qū)表中每個(gè)分區(qū)的每個(gè)分區(qū)的RelOptInfo,partexprs是分區(qū)鍵表達(dá)式,partitioned_child_rels是關(guān)系中未修剪(unpruned)分區(qū)的RT索引.unpruned是指查詢(xún)分區(qū)表時(shí),涉及的相關(guān)分區(qū),比如 where c1 = 1 OR c1 = 2涉及的分區(qū)只有t_hash_partition_1和t_hash_partition_3,則在partitioned_child_rels中只有這兩個(gè)分區(qū)的信息.
如何pruned,下節(jié)介紹

/*----------
 * RelOptInfo
 *      Per-relation information for planning/optimization
 *      規(guī)劃器/優(yōu)化器使用的關(guān)系信息結(jié)構(gòu)體
 *
 * For planning purposes, a "base rel" is either a plain relation (a table)
 * or the output of a sub-SELECT or function that appears in the range table.
 * In either case it is uniquely identified by an RT index.  A "joinrel"
 * is the joining of two or more base rels.  A joinrel is identified by
 * the set of RT indexes for its component baserels.  We create RelOptInfo
 * nodes for each baserel and joinrel, and store them in the PlannerInfo's
 * simple_rel_array and join_rel_list respectively.
 * 出于計(jì)劃目的丘薛,“base rel”要么是一個(gè)普通關(guān)系(表)蜈敢,
 *   要么是出現(xiàn)在范圍表中的子查詢(xún)或函數(shù)的輸出。
 * 在這兩種情況下,它都是由RT索引惟一標(biāo)識(shí)的。
 * "joinrel"是兩個(gè)或兩個(gè)以上的base rels連接。
 * 一個(gè)joinrel是由它的baserels的RT索引集標(biāo)識(shí)弄兜。
 * 我們?yōu)槊總€(gè)baserel和joinrel分別創(chuàng)建RelOptInfo節(jié)點(diǎn),
 *   并將它們分別存儲(chǔ)在PlannerInfo的simple_rel_array和join_rel_list中。
 *
 * Note that there is only one joinrel for any given set of component
 * baserels, no matter what order we assemble them in; so an unordered
 * set is the right datatype to identify it with.
 * 請(qǐng)注意替饿,對(duì)于任何給定的base rels语泽,無(wú)論我們以何種順序組合它們,
 *   都只有一個(gè)連接件;因此视卢,一個(gè)無(wú)序的集合正好是標(biāo)識(shí)它的數(shù)據(jù)類(lèi)型踱卵。
 *
 * We also have "other rels", which are like base rels in that they refer to
 * single RT indexes; but they are not part of the join tree, and are given
 * a different RelOptKind to identify them.
 * Currently the only kind of otherrels are those made for member relations
 * of an "append relation", that is an inheritance set or UNION ALL subquery.
 * An append relation has a parent RTE that is a base rel, which represents
 * the entire append relation.  The member RTEs are otherrels.  The parent
 * is present in the query join tree but the members are not.  The member
 * RTEs and otherrels are used to plan the scans of the individual tables or
 * subqueries of the append set; then the parent baserel is given Append
 * and/or MergeAppend paths comprising the best paths for the individual
 * member rels.  (See comments for AppendRelInfo for more information.)
 * 同時(shí)存在“other rels”,類(lèi)似于base rels据过,它們同樣都指向單個(gè)RT索引;
 *   但是它們不是join樹(shù)的一部分惋砂,并且被賦予不同的RelOptKind來(lái)標(biāo)識(shí)它們。
 * 目前唯一的其他類(lèi)型是那些為“append relation”的成員關(guān)系而創(chuàng)建的绳锅,
 *   即繼承集或UNION ALL子查詢(xún)西饵。
 * 一個(gè)append relation有一個(gè)父RTE,它是一個(gè)基礎(chǔ)rel鳞芙,表示整個(gè)append relation眷柔。
 * 其他成員RTEs是otherrel.。
 * 父節(jié)點(diǎn)存在于查詢(xún)的連接樹(shù)中原朝,但成員無(wú)需存儲(chǔ)在連接樹(shù)中驯嘱。
 * 成員RTEs和otherrels用于計(jì)劃對(duì)append set的單表或子查詢(xún)的掃描;
 *   然后給出parent base rel的APPEND路徑和/或MergeAppend路徑,這些路徑包含單個(gè)成員rels的最佳路徑竿拆。
 * (更多信息請(qǐng)參見(jiàn)AppendRelInfo的注釋宙拉。)
 * 
 * At one time we also made otherrels to represent join RTEs, for use in
 * handling join alias Vars.  Currently this is not needed because all join
 * alias Vars are expanded to non-aliased form during preprocess_expression.
 * 曾經(jīng),還制作了其他的樹(shù)來(lái)表示連接rte丙笋,用于處理連接別名Vars。
 * 目前不需要這樣做煌贴,因?yàn)樵趐reprocess_expression期間御板,所有連接別名Vars都被擴(kuò)展為非別名形式。
 *
 * We also have relations representing joins between child relations of
 * different partitioned tables. These relations are not added to
 * join_rel_level lists as they are not joined directly by the dynamic
 * programming algorithm.
 * 還有表示不同分區(qū)表的子關(guān)系之間的連接的關(guān)系牛郑。
 * 這些關(guān)系不會(huì)添加到j(luò)oin_rel_level鏈表中怠肋,因?yàn)閯?dòng)態(tài)規(guī)劃算法不會(huì)直接連接它們。
 *
 * There is also a RelOptKind for "upper" relations, which are RelOptInfos
 * that describe post-scan/join processing steps, such as aggregation.
 * Many of the fields in these RelOptInfos are meaningless, but their Path
 * fields always hold Paths showing ways to do that processing step.
 * 還有一種RelOptKind表示“upper”關(guān)系淹朋,
 *   即描述掃描/連接后處理步驟(如聚合)的RelOptInfos笙各。
 * 這些RelOptInfos中的許多字段都是沒(méi)有意義的,
 *   但是它們的Path字段總是包含顯示執(zhí)行該處理步驟的路徑础芍。
 * 
 * Lastly, there is a RelOptKind for "dead" relations, which are base rels
 * that we have proven we don't need to join after all.
 * 最后杈抢,還有一種關(guān)系是“DEAD”的關(guān)系,在規(guī)劃期間已經(jīng)證明不需要把此關(guān)系加入連接仑性。
 * 
 * Parts of this data structure are specific to various scan and join
 * mechanisms.  It didn't seem worth creating new node types for them.
 * 該數(shù)據(jù)結(jié)構(gòu)的某些部分特定于各種掃描和連接機(jī)制惶楼。
 * 但似乎不值得為它們創(chuàng)建新的節(jié)點(diǎn)類(lèi)型。
 * 
 *      relids - Set of base-relation identifiers; it is a base relation
 *              if there is just one, a join relation if more than one
 *      relids - 基礎(chǔ)關(guān)系標(biāo)識(shí)符的集合;如只有一個(gè)則為基礎(chǔ)關(guān)系,
 *               如有多個(gè)則為連接關(guān)系
 *      rows - estimated number of tuples in the relation after restriction
 *             clauses have been applied (ie, output rows of a plan for it)
 *      rows - 應(yīng)用約束條件子句后關(guān)系中元組的估算數(shù)目(即計(jì)劃的輸出行數(shù))
 *      consider_startup - true if there is any value in keeping plain paths for
 *                         this rel on the basis of having cheap startup cost
 *      consider_startup - 如果在具有低啟動(dòng)成本的基礎(chǔ)上為這個(gè)rel保留訪問(wèn)路徑有價(jià)值,則為真
 *      consider_param_startup - the same for parameterized paths
 *      consider_param_startup - 與parameterized訪問(wèn)路徑一致
 *      reltarget - Default Path output tlist for this rel; normally contains
 *                  Var and PlaceHolderVar nodes for the values we need to
 *                  output from this relation.
 *                  List is in no particular order, but all rels of an
 *                  appendrel set must use corresponding orders.
 *                  NOTE: in an appendrel child relation, may contain
 *                  arbitrary expressions pulled up from a subquery!
 *      reltarget - 該rel的默認(rèn)路徑輸出投影列;通常會(huì)包含Var和PlaceHolderVar
 *      pathlist - List of Path nodes, one for each potentially useful
 *                 method of generating the relation
 *                 訪問(wèn)路徑節(jié)點(diǎn)鏈表, 存儲(chǔ)每一種可能有用的生成關(guān)系的方法
 *      ppilist - ParamPathInfo nodes for parameterized Paths, if any
 *                參數(shù)化路徑的ParamPathInfo節(jié)點(diǎn)(如果有的話(huà))
 *      cheapest_startup_path - the pathlist member with lowest startup cost
 *          (regardless of ordering) among the unparameterized paths;
 *          or NULL if there is no unparameterized path
 *          在非參數(shù)化路徑中啟動(dòng)成本最低(無(wú)論順序如何)的路徑鏈表成員;
 *              如果沒(méi)有非參數(shù)化路徑歼捐,則為NULL
 *      cheapest_total_path - the pathlist member with lowest total cost
 *          (regardless of ordering) among the unparameterized paths;
 *          or if there is no unparameterized path, the path with lowest
 *          total cost among the paths with minimum parameterization
 *          在非參數(shù)化路徑中總成本最低(無(wú)論順序如何)的路徑列表成員;
 *              如果沒(méi)有非參數(shù)化路徑何陆,則在參數(shù)化最少的路徑中總成本最低的路徑
 *      cheapest_unique_path - for caching cheapest path to produce unique
 *          (no duplicates) output from relation; NULL if not yet requested
 *          用于緩存最便宜的路徑,以便從關(guān)系中產(chǎn)生唯一(無(wú)重復(fù))輸出;
 *              如果無(wú)此要求豹储,則為NULL
 *      cheapest_parameterized_paths - best paths for their parameterizations;
 *          always includes cheapest_total_path, even if that's unparameterized
 *          參數(shù)化的最佳路徑;總是包含cheapest_total_path贷盲,即使它是非參數(shù)化的       
 *      direct_lateral_relids - rels this rel has direct LATERAL references to
 *          該rel直接LATERAL依賴(lài)的rels
 *      lateral_relids - required outer rels for LATERAL, as a Relids set
 *          (includes both direct and indirect lateral references)
 *          LATERAL所需的外部rels,作為Relids集合(包括直接和間接的側(cè)向參考)     
 *
 * If the relation is a base relation it will have these fields set:
 * 如果關(guān)系是一個(gè)基本關(guān)系剥扣,它將設(shè)置這些字段:
 *      relid - RTE index (this is redundant with the relids field, but
 *              is provided for convenience of access)
 *          RTE索引(這對(duì)于relids字段來(lái)說(shuō)是冗余的晃洒,但是為了方便訪問(wèn)而提供)            
 *      rtekind - copy of RTE's rtekind field
 *          RTE's rtekind字段的拷貝
 *      min_attr, max_attr - range of valid AttrNumbers for rel
 *          關(guān)系有效AttrNumbers的范圍(最大/最小編號(hào))
 *      attr_needed - array of bitmapsets indicating the highest joinrel
 *              in which each attribute is needed; if bit 0 is set then
 *              the attribute is needed as part of final targetlist
 *          位圖集數(shù)組,表示每個(gè)屬性所需的最高層joinrel;
 *              如果設(shè)置為0朦乏,則需要將該屬性作為最終targetlist的一部分      
 *      attr_widths - cache space for per-attribute width estimates;
 *                    zero means not computed yet
 *          用于每個(gè)屬性寬度估計(jì)的緩存空間;0表示還沒(méi)有計(jì)算
 *      lateral_vars - lateral cross-references of rel, if any (list of
 *                     Vars and PlaceHolderVars)
 *          rel的lateral交叉參照球及,如果有的話(huà)(Vars和PlaceHolderVars鏈表)
 *      lateral_referencers - relids of rels that reference this one laterally
 *              (includes both direct and indirect lateral references)
 *          lateral依賴(lài)此關(guān)系的relids(包括直接&間接lateral依賴(lài))
 *      indexlist - list of IndexOptInfo nodes for relation's indexes
 *                  (always NIL if it's not a table)
 *          關(guān)系索引的IndexOptInfo節(jié)點(diǎn)鏈表(如果不是表,總是NIL)  
 *      pages - number of disk pages in relation (zero if not a table)
 *          關(guān)系的磁盤(pán)頁(yè)數(shù)(如不是表,則為0)
 *      tuples - number of tuples in relation (not considering restrictions)
 *          關(guān)系的元組數(shù)統(tǒng)計(jì)(還沒(méi)有考慮約束條件)
 *      allvisfrac - fraction of disk pages that are marked all-visible
 *          標(biāo)記為all-visible的磁盤(pán)頁(yè)數(shù)比例
 *      subroot - PlannerInfo for subquery (NULL if it's not a subquery)
 *          用于子查詢(xún)的PlannerInfo(如果不是子查詢(xún)呻疹,則為NULL)
 *      subplan_params - list of PlannerParamItems to be passed to subquery
 *          要傳遞給子查詢(xún)的PlannerParamItems的鏈表
 *      Note: for a subquery, tuples and subroot are not set immediately
 *      upon creation of the RelOptInfo object; they are filled in when
 *      set_subquery_pathlist processes the object.
 *      對(duì)于子查詢(xún)吃引,元組和subroot不會(huì)在創(chuàng)建RelOptInfo對(duì)象時(shí)立即設(shè)置;
 *          它們是在set_subquery_pathlist處理對(duì)象時(shí)填充的。
 *
 *      For otherrels that are appendrel members, these fields are filled
 *      in just as for a baserel, except we don't bother with lateral_vars.
 *      對(duì)于其他appendrel成員刽锤,這些字段就像base rels一樣被填充镊尺,
 *          除了我們不關(guān)心的lateral_vars。
 *
 * If the relation is either a foreign table or a join of foreign tables that
 * all belong to the same foreign server and are assigned to the same user to
 * check access permissions as (cf checkAsUser), these fields will be set:
 * 如果關(guān)系是一個(gè)外表或一個(gè)外表的連接并思,這些表都屬于相同的外服務(wù)器
 *   并被分配給相同的用戶(hù)來(lái)檢查訪問(wèn)權(quán)限(cf checkAsUser)庐氮,這些字段將被設(shè)置:
 *
 *      serverid - OID of foreign server, if foreign table (else InvalidOid)
 *          外部服務(wù)器的OID,如不為外部表則為InvalidOid
 *      userid - OID of user to check access as (InvalidOid means current user)
 *          檢查訪問(wèn)權(quán)限的用戶(hù)OID(InvalidOid表示當(dāng)前用戶(hù))
 *      useridiscurrent - we've assumed that userid equals current user
 *          我們假設(shè)userid為當(dāng)前用戶(hù)
 *      fdwroutine - function hooks for FDW, if foreign table (else NULL)
 *          FDW的函數(shù)鉤子,如不是外部表則為NULL
 *      fdw_private - private state for FDW, if foreign table (else NULL)
 *          FDW的私有狀態(tài),不是外部表則為NULL
 *
 * Two fields are used to cache knowledge acquired during the join search
 * about whether this rel is provably unique when being joined to given other
 * relation(s), ie, it can have at most one row matching any given row from
 * that join relation.  Currently we only attempt such proofs, and thus only
 * populate these fields, for base rels; but someday they might be used for
 * join rels too:
 * 下面的兩個(gè)字段用于緩存在連接搜索過(guò)程中獲取的信息宋彼,
 *     這些信息是關(guān)于當(dāng)這個(gè)rel被連接到給定的其他關(guān)系時(shí)是否被證明是唯一的弄砍,
 *     也就是說(shuō),它最多只能有一行匹配來(lái)自該連接關(guān)系的任何給定行输涕。
 * 目前我們只嘗試這樣的證明音婶,因此只填充這些字段,用于base rels;
 * 但總有一天它們也可以被用來(lái)加入join rels:
 *
 *      unique_for_rels - list of Relid sets, each one being a set of other
 *                  rels for which this one has been proven unique
 *          Relid集合的鏈表莱坎,每一個(gè)都是一組other rels,這些rels已經(jīng)被證明是唯一的
 *      non_unique_for_rels - list of Relid sets, each one being a set of
 *                  other rels for which we have tried and failed to prove
 *                  this one unique
 *          Relid集合的鏈表衣式,每個(gè)集合都是other rels,這些rels試圖證明唯一的檐什,但失敗了
 *
 * The presence of the following fields depends on the restrictions
 * and joins that the relation participates in:
 * 以下字段的存在取決于約束條件和關(guān)系所參與的連接:
 *
 *      baserestrictinfo - List of RestrictInfo nodes, containing info about
 *                  each non-join qualification clause in which this relation
 *                  participates (only used for base rels)
 *          RestrictInfo節(jié)點(diǎn)鏈表碴卧,其中包含關(guān)于此關(guān)系參與的每個(gè)非連接限定子句的信息(僅用于基礎(chǔ)rels)
 *      baserestrictcost - Estimated cost of evaluating the baserestrictinfo
 *                  clauses at a single tuple (only used for base rels)
 *          在單個(gè)元組中解析baserestrictinfo子句的估算成本(僅用于基礎(chǔ)rels)
 *      baserestrict_min_security - Smallest security_level found among
 *                  clauses in baserestrictinfo
 *          在baserestrictinfo子句中找到的最小security_level
 *      joininfo  - List of RestrictInfo nodes, containing info about each
 *                  join clause in which this relation participates (but
 *                  note this excludes clauses that might be derivable from
 *                  EquivalenceClasses)
 *          RestrictInfo節(jié)點(diǎn)鏈表,其中包含關(guān)于此關(guān)系參與的每個(gè)連接條件子句的信息
 *          (但請(qǐng)注意乃正,這排除了可能從等價(jià)類(lèi)派生的子句)
 *      has_eclass_joins - flag that EquivalenceClass joins are possible
 *          用于標(biāo)記等價(jià)類(lèi)連接是可能的
 *
 * Note: Keeping a restrictinfo list in the RelOptInfo is useful only for
 * base rels, because for a join rel the set of clauses that are treated as
 * restrict clauses varies depending on which sub-relations we choose to join.
 * (For example, in a 3-base-rel join, a clause relating rels 1 and 2 must be
 * treated as a restrictclause if we join {1} and {2 3} to make {1 2 3}; but
 * if we join {1 2} and {3} then that clause will be a restrictclause in {1 2}
 * and should not be processed again at the level of {1 2 3}.)  Therefore,
 * the restrictinfo list in the join case appears in individual JoinPaths
 * (field joinrestrictinfo), not in the parent relation.  But it's OK for
 * the RelOptInfo to store the joininfo list, because that is the same
 * for a given rel no matter how we form it.
 * 注意:在RelOptInfo中保存一個(gè)restrictinfo鏈表只對(duì)基礎(chǔ)rels有用住册,
 *     因?yàn)閷?duì)于一個(gè)join rel,被視為限制子句的子句集會(huì)根據(jù)我們選擇加入的子關(guān)系而變化烫葬。(例如界弧,在一個(gè)3-base-rel連接中凡蜻,如果我們加入{1}和{2 3}以生成{1 2 3},則與efs 1和2相關(guān)的子句必須被視為限制性子句;但是如果我們加入{1 2}和{3}垢箕,那么該子句將是{1 2}中的一個(gè)限制性子句划栓,不應(yīng)該在{1 2 3}的級(jí)別上再次處理)。因此条获,在join案例中忠荞,節(jié)流信息列表出現(xiàn)在單獨(dú)的連接路徑(字段join節(jié)流信息)中,而不是在父關(guān)系中帅掘。但是RelOptInfo可以存儲(chǔ)joininfo列表委煤,因?yàn)閷?duì)于給定的rel,無(wú)論我們?nèi)绾涡纬伤际且粯拥摹? *
 * We store baserestrictcost in the RelOptInfo (for base relations) because
 * we know we will need it at least once (to price the sequential scan)
 * and may need it multiple times to price index scans.
 * 我們將baserestrictcost存儲(chǔ)在RelOptInfo(用于基本關(guān)系)中修档,
 *     因?yàn)槲覀冎乐辽傩枰淮?為順序掃描計(jì)算成本)碧绞,并且可能需要它多次來(lái)為索引掃描計(jì)算成本。
 *
 * If the relation is partitioned, these fields will be set:
 * 如果關(guān)系是分區(qū)表,會(huì)設(shè)置這些字段:
 *
 *      part_scheme - Partitioning scheme of the relation
 *          關(guān)系的分區(qū)schema
 *      nparts - Number of partitions
 *          關(guān)系的分區(qū)數(shù)
 *      boundinfo - Partition bounds
 *          分區(qū)邊界信息
 *      partition_qual - Partition constraint if not the root
 *          如非root,則該字段存儲(chǔ)分區(qū)約束條件
 *      part_rels - RelOptInfos for each partition
 *          每個(gè)分區(qū)的RelOptInfos
 *      partexprs, nullable_partexprs - Partition key expressions
 *          分區(qū)鍵表達(dá)式
 *      partitioned_child_rels - RT indexes of unpruned partitions of
 *                               this relation that are partitioned tables
 *                               themselves, in hierarchical order
 *          關(guān)系中未修剪(unpruned)分區(qū)的RT索引吱窝,
 *              這些分區(qū)本身就是分區(qū)表讥邻,按層次順序排列
 *
 * Note: A base relation always has only one set of partition keys, but a join
 * relation may have as many sets of partition keys as the number of relations
 * being joined. partexprs and nullable_partexprs are arrays containing
 * part_scheme->partnatts elements each. Each of these elements is a list of
 * partition key expressions.  For a base relation each list in partexprs
 * contains only one expression and nullable_partexprs is not populated. For a
 * join relation, partexprs and nullable_partexprs contain partition key
 * expressions from non-nullable and nullable relations resp. Lists at any
 * given position in those arrays together contain as many elements as the
 * number of joining relations.
 * 注意:一個(gè)基本關(guān)系總是只有一組分區(qū)鍵,
 *   但是連接關(guān)系的分區(qū)鍵可能與被連接的關(guān)系的數(shù)量一樣多院峡。
 * partexprs和nullable_partexp是分別包含part_scheme->partnatts元素的數(shù)組兴使。
 * 每個(gè)元素都是分區(qū)鍵表達(dá)式的鏈表。
 * 對(duì)于基本關(guān)系照激,partexprs中的每個(gè)鏈表只包含一個(gè)表達(dá)式发魄,
 *   并且不填充nullable_partexprs。
 * 對(duì)于連接關(guān)系俩垃,partexprs和nullable_partexprs包含來(lái)自非空和可空關(guān)系resp的分區(qū)鍵表達(dá)式励幼。
 * 這些數(shù)組中任意給定位置的鏈表包含的元素與連接關(guān)系的數(shù)量一樣多。
 *----------
 */
typedef enum RelOptKind
{
    RELOPT_BASEREL,//基本關(guān)系(如基表/子查詢(xún)等)
    RELOPT_JOINREL,//連接產(chǎn)生的關(guān)系,要注意的是通過(guò)連接等方式產(chǎn)生的結(jié)果亦可以視為關(guān)系
    RELOPT_OTHER_MEMBER_REL,
    RELOPT_OTHER_JOINREL,
    RELOPT_UPPER_REL,//上層的關(guān)系
    RELOPT_OTHER_UPPER_REL,
    RELOPT_DEADREL
} RelOptKind;

/*
 * Is the given relation a simple relation i.e a base or "other" member
 * relation?
 */
#define IS_SIMPLE_REL(rel) \
    ((rel)->reloptkind == RELOPT_BASEREL || \
     (rel)->reloptkind == RELOPT_OTHER_MEMBER_REL)

/* Is the given relation a join relation? */
#define IS_JOIN_REL(rel)    \
    ((rel)->reloptkind == RELOPT_JOINREL || \
     (rel)->reloptkind == RELOPT_OTHER_JOINREL)

/* Is the given relation an upper relation? */
#define IS_UPPER_REL(rel)   \
    ((rel)->reloptkind == RELOPT_UPPER_REL || \
     (rel)->reloptkind == RELOPT_OTHER_UPPER_REL)

/* Is the given relation an "other" relation? */
#define IS_OTHER_REL(rel) \
    ((rel)->reloptkind == RELOPT_OTHER_MEMBER_REL || \
     (rel)->reloptkind == RELOPT_OTHER_JOINREL || \
     (rel)->reloptkind == RELOPT_OTHER_UPPER_REL)

typedef struct RelOptInfo
{
    //節(jié)點(diǎn)標(biāo)識(shí)
    NodeTag     type;
    //RelOpt類(lèi)型
    RelOptKind  reloptkind;

    /* all relations included in this RelOptInfo */
    //所有關(guān)系都有的屬性
    //Relids(rtindex)集合
    Relids      relids;         /* set of base relids (rangetable indexes) */

    /* size estimates generated by planner */
    //規(guī)劃器生成的大小估算
    //結(jié)果元組的估算數(shù)量
    double      rows;           /* estimated number of result tuples */

    /* per-relation planner control flags */
    //規(guī)劃器使用的每個(gè)關(guān)系的控制標(biāo)記
    //是否考慮啟動(dòng)成本?是,需要保留啟動(dòng)成本低的路徑
    bool        consider_startup;   /* keep cheap-startup-cost paths? */
    //是否考慮參數(shù)化?的路徑 
    bool        consider_param_startup; /* ditto for parameterized paths? */
    //是否考慮并行處理路徑
    bool        consider_parallel;  /* consider parallel paths? */

    /* default result targetlist for Paths scanning this relation */
    //掃描該Relation時(shí)默認(rèn)的結(jié)果投影列
    //Vars/Exprs,成本,行平均大小鏈表
    struct PathTarget *reltarget;   /* list of Vars/Exprs, cost, width */

    /* materialization information */
    //物化信息
    //訪問(wèn)路徑鏈表
    List       *pathlist;       /* Path structures */
    //路徑鏈表中的ParamPathInfos鏈表
    List       *ppilist;        /* ParamPathInfos used in pathlist */
    //并行部分路徑
    List       *partial_pathlist;   /* partial Paths */
    //啟動(dòng)代價(jià)最低的路徑
    struct Path *cheapest_startup_path;
    //整體代價(jià)最低的路徑
    struct Path *cheapest_total_path;
    //獲取唯一值代價(jià)最低的路徑
    struct Path *cheapest_unique_path;
    //參數(shù)化代價(jià)最低的路徑
    List       *cheapest_parameterized_paths;

    /* parameterization information needed for both base rels and join rels */
    /* (see also lateral_vars and lateral_referencers) */
    //基本通道和連接通道都需要參數(shù)化信息
    //(參考lateral_vars和lateral_referencers)
    //使用lateral語(yǔ)法,需依賴(lài)的Relids
    Relids      direct_lateral_relids;  /* rels directly laterally referenced */
    //rel的最小化參數(shù)信息
    Relids      lateral_relids; /* minimum parameterization of rel */

    /* information about a base rel (not set for join rels!) */
    //reloptkind=RELOPT_BASEREL時(shí)使用的數(shù)據(jù)結(jié)構(gòu)
    //relid
    Index       relid;           /* Relation ID */
    //表空間
    Oid         reltablespace;  /*  containing tablespace */
    //類(lèi)型:基表?子查詢(xún)?還是函數(shù)等等?
    RTEKind     rtekind;        /* RELATION, SUBQUERY, FUNCTION, etc */
    //最小的屬性編號(hào)
    AttrNumber  min_attr;       /*  smallest attrno of rel (often <0) */
    //最大的屬性編號(hào)
    AttrNumber  max_attr;       /*  largest attrno of rel */
    //屬性數(shù)組
    Relids     *attr_needed;    /*  array indexed [min_attr .. max_attr] */
    //屬性寬度
    int32      *attr_widths;    /*  array indexed [min_attr .. max_attr] */
    //關(guān)系依賴(lài)的LATERAL Vars/PHVs
    List       *lateral_vars;   /*  LATERAL Vars and PHVs referenced by rel */
    //依賴(lài)該關(guān)系的Relids
    Relids      lateral_referencers;    /* rels that reference me laterally */
    //該關(guān)系的IndexOptInfo鏈表
    List       *indexlist;      /*  list of IndexOptInfo */
    //統(tǒng)計(jì)信息鏈表
    List       *statlist;       /*  list of StatisticExtInfo */
    //塊數(shù)
    BlockNumber pages;          /*  size estimates derived from pg_class */
    //元組數(shù)
    double      tuples;      /*  */
    //
    double      allvisfrac;  /* ? */
    //如為子查詢(xún),存儲(chǔ)子查詢(xún)的root
    PlannerInfo *subroot;       /*  if subquery */
    //如為子查詢(xún),存儲(chǔ)子查詢(xún)的參數(shù)
    List       *subplan_params; /*  if subquery */
    //并行執(zhí)行,需要多少個(gè)workers?
    int         rel_parallel_workers;   /*  wanted number of parallel workers */

    /* Information about foreign tables and foreign joins */
    //FWD相關(guān)信息
    //表或連接的服務(wù)器標(biāo)識(shí)符
    Oid         serverid;       /* identifies server for the table or join */
    //用戶(hù)id標(biāo)識(shí)
    Oid         userid;         /* identifies user to check access as */
    //對(duì)于當(dāng)前用戶(hù)來(lái)說(shuō),連接才是有效的
    bool        useridiscurrent;    /* join is only valid for current user */
    /* use "struct FdwRoutine" to avoid including fdwapi.h here */
    //使用結(jié)構(gòu)體FdwRoutine,避免包含頭文件fdwapi.h
    struct FdwRoutine *fdwroutine;
    void       *fdw_private;

    /* cache space for remembering if we have proven this relation unique */
    //如果已證明該關(guān)系是唯一的,那么這些是用于緩存這些信息的字段
    //已知的,可保證唯一的Relids鏈表
    List       *unique_for_rels;    /* known unique for these other relid
                                     * set(s) */
    //已知的,不唯一的Relids鏈表
    List       *non_unique_for_rels;    /*  known not unique for these set(s) */

    /* used by various scans and joins: */
    //用于各種掃描和連接
    //如為基本關(guān)系,存儲(chǔ)約束條件鏈表
    List       *baserestrictinfo;   /*  RestrictInfo structures (if base rel) */
    //解析約束表達(dá)式的成本?
    QualCost    baserestrictcost;   /*  cost of evaluating the above */
    //最低安全等級(jí)
    Index       baserestrict_min_security;  /*  min security_level found in
                                             * baserestrictinfo */
    //連接語(yǔ)句的約束條件信息
    List       *joininfo;       /*  RestrictInfo structures for join clauses
                                 * involving this rel */
    //是否存在等價(jià)類(lèi)連接?
    bool        has_eclass_joins;   /*  T means joininfo is incomplete */

    /* used by partitionwise joins: */
    //partitionwise連接使用的字段
    //是否考慮使用partitionwise join?
    bool        consider_partitionwise_join;    /* consider partitionwise
                                                 * join paths? (if
                                                 * partitioned rel) */
    //最高層的父關(guān)系Relids
    Relids      top_parent_relids;  /* Relids of topmost parents (if "other"
                                     * rel) */

    /* used for partitioned relations */
     //分區(qū)表使用
    //分區(qū)的schema 
    PartitionScheme part_scheme;    /* Partitioning scheme. */
    //分區(qū)數(shù) 
    int         nparts;         /* number of partitions */
    //分區(qū)邊界信息 
    struct PartitionBoundInfoData *boundinfo;   /* Partition bounds */
    //分區(qū)約束
    List       *partition_qual; /*  partition constraint */
    //分區(qū)的RelOptInfo數(shù)組 
    struct RelOptInfo **part_rels;  /* Array of RelOptInfos of partitions,
                                     * stored in the same order of bounds */
    //非空分區(qū)鍵表達(dá)式鏈表
    List      **partexprs;      /* Non-nullable partition key expressions. */
    //可為空的分區(qū)鍵表達(dá)式 
    List      **nullable_partexprs; /* Nullable partition key expressions. */
    // 分區(qū)子表RT Indexes鏈表 
    List       *partitioned_child_rels; /*List of RT indexes. */
} RelOptInfo;

AppendRelInfo
Append-relation信息.
當(dāng)我們將可繼承表(分區(qū)表)或UNION-ALL子查詢(xún)展開(kāi)為“追加關(guān)系”(本質(zhì)上是子RTE的鏈表)時(shí)吆寨,為每個(gè)子RTE構(gòu)建一個(gè)AppendRelInfo赏淌。
AppendRelInfos鏈表指示在展開(kāi)父節(jié)點(diǎn)時(shí)必須包含哪些子rte,每個(gè)節(jié)點(diǎn)具有將引用父節(jié)點(diǎn)的Vars轉(zhuǎn)換為引用該子節(jié)點(diǎn)的Vars所需的所有信息啄清。

/*
 * Append-relation info.
 * Append-relation信息.
 * 
 * When we expand an inheritable table or a UNION-ALL subselect into an
 * "append relation" (essentially, a list of child RTEs), we build an
 * AppendRelInfo for each child RTE.  The list of AppendRelInfos indicates
 * which child RTEs must be included when expanding the parent, and each node
 * carries information needed to translate Vars referencing the parent into
 * Vars referencing that child.
 * 當(dāng)我們將可繼承表(分區(qū)表)或UNION-ALL子查詢(xún)展開(kāi)為“追加關(guān)系”(本質(zhì)上是子RTE的鏈表)時(shí),
 *   為每個(gè)子RTE構(gòu)建一個(gè)AppendRelInfo俺孙。
 * AppendRelInfos鏈表指示在展開(kāi)父節(jié)點(diǎn)時(shí)必須包含哪些子rte辣卒,
 *   每個(gè)節(jié)點(diǎn)具有將引用父節(jié)點(diǎn)的Vars轉(zhuǎn)換為引用該子節(jié)點(diǎn)的Vars所需的所有信息。
 * 
 * These structs are kept in the PlannerInfo node's append_rel_list.
 * Note that we just throw all the structs into one list, and scan the
 * whole list when desiring to expand any one parent.  We could have used
 * a more complex data structure (eg, one list per parent), but this would
 * be harder to update during operations such as pulling up subqueries,
 * and not really any easier to scan.  Considering that typical queries
 * will not have many different append parents, it doesn't seem worthwhile
 * to complicate things.
 * 這些結(jié)構(gòu)體保存在PlannerInfo節(jié)點(diǎn)的append_rel_list中睛榄。
 * 注意,只是將所有的結(jié)構(gòu)體放入一個(gè)鏈表中,并在希望展開(kāi)任何父類(lèi)時(shí)掃描整個(gè)鏈表檀葛。
 * 本可以使用更復(fù)雜的數(shù)據(jù)結(jié)構(gòu)(例如忠怖,每個(gè)父節(jié)點(diǎn)一個(gè)列表)港准,
 *   但是在提取子查詢(xún)之類(lèi)的操作中更新它會(huì)更困難,
 *   而且實(shí)際上也不會(huì)更容易掃描咧欣。
 * 考慮到典型的查詢(xún)不會(huì)有很多不同的附加項(xiàng)浅缸,因此似乎不值得將事情復(fù)雜化。
 * 
 * Note: after completion of the planner prep phase, any given RTE is an
 * append parent having entries in append_rel_list if and only if its
 * "inh" flag is set.  We clear "inh" for plain tables that turn out not
 * to have inheritance children, and (in an abuse of the original meaning
 * of the flag) we set "inh" for subquery RTEs that turn out to be
 * flattenable UNION ALL queries.  This lets us avoid useless searches
 * of append_rel_list.
 * 注意:計(jì)劃準(zhǔn)備階段完成后,
 *   當(dāng)且僅當(dāng)它的“inh”標(biāo)志已設(shè)置時(shí),給定的RTE是一個(gè)append parent在append_rel_list中的一個(gè)條目魄咕。
 * 我們?yōu)闆](méi)有child的平面表清除“inh”標(biāo)記,
 *   同時(shí)(有濫用標(biāo)記的嫌疑)為UNION ALL查詢(xún)中的子查詢(xún)RTEs設(shè)置“inh”標(biāo)記衩椒。
 * 這樣可以避免對(duì)append_rel_list進(jìn)行無(wú)用的搜索。
 * 
 * Note: the data structure assumes that append-rel members are single
 * baserels.  This is OK for inheritance, but it prevents us from pulling
 * up a UNION ALL member subquery if it contains a join.  While that could
 * be fixed with a more complex data structure, at present there's not much
 * point because no improvement in the plan could result.
 * 注意:數(shù)據(jù)結(jié)構(gòu)假定附加的rel成員是獨(dú)立的baserels哮兰。
 * 這對(duì)于繼承來(lái)說(shuō)是可以的毛萌,但是如果UNION ALL member子查詢(xún)包含一個(gè)join,
 *   那么它將阻止我們提取UNION ALL member子查詢(xún)喝滞。
 * 雖然可以用更復(fù)雜的數(shù)據(jù)結(jié)構(gòu)解決這個(gè)問(wèn)題阁将,但目前沒(méi)有太大意義,因?yàn)樵撚?jì)劃可能不會(huì)有任何改進(jìn)右遭。
 */

typedef struct AppendRelInfo
{
    NodeTag     type;

    /*
     * These fields uniquely identify this append relationship.  There can be
     * (in fact, always should be) multiple AppendRelInfos for the same
     * parent_relid, but never more than one per child_relid, since a given
     * RTE cannot be a child of more than one append parent.
     * 這些字段惟一地標(biāo)識(shí)這個(gè)append relationship做盅。
     * 對(duì)于同一個(gè)parent_relid可以有(實(shí)際上應(yīng)該總是)多個(gè)AppendRelInfos,
     *   但是每個(gè)child_relid不能有多個(gè)AppendRelInfos狸演,
     *   因?yàn)榻o定的RTE不能是多個(gè)append parent的子節(jié)點(diǎn)言蛇。
     */
    Index       parent_relid;   /* parent rel的RT索引;RT index of append parent rel */
    Index       child_relid;    /* child rel的RT索引;RT index of append child rel */

    /*
     * For an inheritance appendrel, the parent and child are both regular
     * relations, and we store their rowtype OIDs here for use in translating
     * whole-row Vars.  For a UNION-ALL appendrel, the parent and child are
     * both subqueries with no named rowtype, and we store InvalidOid here.
     * 對(duì)于繼承appendrel,父類(lèi)和子類(lèi)都是普通關(guān)系宵距,
     *   我們將它們的rowtype OIDs存儲(chǔ)在這里腊尚,用于轉(zhuǎn)換whole-row Vars。
     * 對(duì)于UNION-ALL appendrel满哪,父查詢(xún)和子查詢(xún)都是沒(méi)有指定行類(lèi)型的子查詢(xún)婿斥,
     * 我們?cè)谶@里存儲(chǔ)InvalidOid。
     */
    Oid         parent_reltype; /* OID of parent's composite type */
    Oid         child_reltype;  /* OID of child's composite type */

    /*
     * The N'th element of this list is a Var or expression representing the
     * child column corresponding to the N'th column of the parent. This is
     * used to translate Vars referencing the parent rel into references to
     * the child.  A list element is NULL if it corresponds to a dropped
     * column of the parent (this is only possible for inheritance cases, not
     * UNION ALL).  The list elements are always simple Vars for inheritance
     * cases, but can be arbitrary expressions in UNION ALL cases.
     * 這個(gè)列表的第N個(gè)元素是一個(gè)Var或表達(dá)式哨鸭,表示與父元素的第N列對(duì)應(yīng)的子列民宿。
     * 這用于將引用parent rel的Vars轉(zhuǎn)換為對(duì)子rel的引用。
     * 如果鏈表元素與父元素的已刪除列相對(duì)應(yīng)像鸡,則該元素為NULL
     *   (這只適用于繼承情況活鹰,而不是UNION ALL)。
     * 對(duì)于繼承情況只估,鏈表元素總是簡(jiǎn)單的變量志群,但是可以是UNION ALL情況下的任意表達(dá)式。
     *
     * Notice we only store entries for user columns (attno > 0).  Whole-row
     * Vars are special-cased, and system columns (attno < 0) need no special
     * translation since their attnos are the same for all tables.
     * 注意蛔钙,我們只存儲(chǔ)用戶(hù)列的條目(attno > 0)锌云。
     * Whole-row Vars是大小寫(xiě)敏感的,系統(tǒng)列(attno < 0)不需要特別的轉(zhuǎn)換吁脱,
     *   因?yàn)樗鼈兊腶ttno對(duì)所有表都是相同的桑涎。
     *
     * Caution: the Vars have varlevelsup = 0.  Be careful to adjust as needed
     * when copying into a subquery.
     * 注意:Vars的varlevelsup = 0彬向。
     * 在將數(shù)據(jù)復(fù)制到子查詢(xún)時(shí),要注意根據(jù)需要進(jìn)行調(diào)整攻冷。
     */
    //child's Vars中的表達(dá)式
    List       *translated_vars;    /* Expressions in the child's Vars */

    /*
     * We store the parent table's OID here for inheritance, or InvalidOid for
     * UNION ALL.  This is only needed to help in generating error messages if
     * an attempt is made to reference a dropped parent column.
     * 我們將父表的OID存儲(chǔ)在這里用于繼承娃胆,
     *   如為UNION ALL,則這里存儲(chǔ)的是InvalidOid。
     * 只有在試圖引用已刪除的父列時(shí)讲衫,才需要這樣做來(lái)幫助生成錯(cuò)誤消息缕棵。
     */
    Oid         parent_reloid;  /* OID of parent relation */
} AppendRelInfo;

PlannerInfo
該數(shù)據(jù)結(jié)構(gòu)用于存儲(chǔ)查詢(xún)語(yǔ)句在規(guī)劃/優(yōu)化過(guò)程中的相關(guān)信息

/*----------
 * PlannerInfo
 *      Per-query information for planning/optimization
 *      用于規(guī)劃/優(yōu)化的每個(gè)查詢(xún)信息
 * 
 * This struct is conventionally called "root" in all the planner routines.
 * It holds links to all of the planner's working state, in addition to the
 * original Query.  Note that at present the planner extensively modifies
 * the passed-in Query data structure; someday that should stop.
 * 在所有計(jì)劃程序例程中,這個(gè)結(jié)構(gòu)通常稱(chēng)為“root”涉兽。
 * 除了原始查詢(xún)之外招驴,它還保存到所有計(jì)劃器工作狀態(tài)的鏈接。
 * 注意枷畏,目前計(jì)劃器會(huì)毫無(wú)節(jié)制的修改傳入的查詢(xún)數(shù)據(jù)結(jié)構(gòu),相信總有一天這種情況會(huì)停止的别厘。
 *----------
 */
struct AppendRelInfo;

typedef struct PlannerInfo
{
    NodeTag     type;//Node標(biāo)識(shí)
    //查詢(xún)樹(shù)
    Query      *parse;          /* the Query being planned */
    //當(dāng)前的planner全局信息
    PlannerGlobal *glob;        /* global info for current planner run */
    //查詢(xún)層次,1標(biāo)識(shí)最高層
    Index       query_level;    /* 1 at the outermost Query */
    // 如為子計(jì)劃,則這里存儲(chǔ)父計(jì)劃器指針,NULL標(biāo)識(shí)最高層
    struct PlannerInfo *parent_root;    /* NULL at outermost Query */

    /*
     * plan_params contains the expressions that this query level needs to
     * make available to a lower query level that is currently being planned.
     * outer_params contains the paramIds of PARAM_EXEC Params that outer
     * query levels will make available to this query level.
     * plan_params包含該查詢(xún)級(jí)別需要提供給當(dāng)前計(jì)劃的較低查詢(xún)級(jí)別的表達(dá)式。
     * outer_params包含PARAM_EXEC Params的參數(shù)拥诡,外部查詢(xún)級(jí)別將使該查詢(xún)級(jí)別可用這些參數(shù)触趴。
     */
    List       *plan_params;    /* list of PlannerParamItems, see below */
    Bitmapset  *outer_params;

    /*
     * simple_rel_array holds pointers to "base rels" and "other rels" (see
     * comments for RelOptInfo for more info).  It is indexed by rangetable
     * index (so entry 0 is always wasted).  Entries can be NULL when an RTE
     * does not correspond to a base relation, such as a join RTE or an
     * unreferenced view RTE; or if the RelOptInfo hasn't been made yet.
     * simple_rel_array保存指向“base rels”和“other rels”的指針
     * (有關(guān)RelOptInfo的更多信息,請(qǐng)參見(jiàn)注釋)渴肉。
     * 它由可范圍表索引建立索引(因此條目0總是被浪費(fèi))冗懦。
     * 當(dāng)RTE與基本關(guān)系(如JOIN RTE或未被引用的視圖RTE時(shí))不相對(duì)應(yīng)
     *   或者如果RelOptInfo還沒(méi)有生成,條目可以為NULL仇祭。
     */
    //RelOptInfo數(shù)組,存儲(chǔ)"base rels",比如基表/子查詢(xún)等.
    //該數(shù)組與RTE的順序一一對(duì)應(yīng),而且是從1開(kāi)始,因此[0]無(wú)用 */
    struct RelOptInfo **simple_rel_array;   /* All 1-rel RelOptInfos */
    int         simple_rel_array_size;  /* 數(shù)組大小,allocated size of array */

    /*
     * simple_rte_array is the same length as simple_rel_array and holds
     * pointers to the associated rangetable entries.  This lets us avoid
     * rt_fetch(), which can be a bit slow once large inheritance sets have
     * been expanded.
     * simple_rte_array的長(zhǎng)度與simple_rel_array相同披蕉,
     *   并保存指向相應(yīng)范圍表?xiàng)l目的指針。
     * 這使我們可以避免執(zhí)行rt_fetch()乌奇,因?yàn)橐坏U(kuò)展了大型繼承集没讲,rt_fetch()可能會(huì)有點(diǎn)慢。
     */
    //RTE數(shù)組
    RangeTblEntry **simple_rte_array;   /* rangetable as an array */

    /*
     * append_rel_array is the same length as the above arrays, and holds
     * pointers to the corresponding AppendRelInfo entry indexed by
     * child_relid, or NULL if none.  The array itself is not allocated if
     * append_rel_list is empty.
     * append_rel_array與上述數(shù)組的長(zhǎng)度相同礁苗,
     *   并保存指向?qū)?yīng)的AppendRelInfo條目的指針爬凑,該條目由child_relid索引,
     *   如果沒(méi)有索引則為NULL试伙。
     * 如果append_rel_list為空嘁信,則不分配數(shù)組本身。
     */
    //處理集合操作如UNION ALL時(shí)使用和分區(qū)表時(shí)使用
    struct AppendRelInfo **append_rel_array;

    /*
     * all_baserels is a Relids set of all base relids (but not "other"
     * relids) in the query; that is, the Relids identifier of the final join
     * we need to form.  This is computed in make_one_rel, just before we
     * start making Paths.
     * all_baserels是查詢(xún)中所有base relids(但不是“other” relids)的一個(gè)Relids集合;
     *   也就是說(shuō)疏叨,這是需要形成的最終連接的Relids標(biāo)識(shí)符吱抚。
     * 這是在開(kāi)始創(chuàng)建路徑之前在make_one_rel中計(jì)算的。
     */
    Relids      all_baserels;//"base rels"

    /*
     * nullable_baserels is a Relids set of base relids that are nullable by
     * some outer join in the jointree; these are rels that are potentially
     * nullable below the WHERE clause, SELECT targetlist, etc.  This is
     * computed in deconstruct_jointree.
     * nullable_baserels是由jointree中的某些外連接中值可為空的base Relids集合;
     *   這些是在WHERE子句考廉、SELECT targetlist等下面可能為空的樹(shù)。
     * 這是在deconstruct_jointree中處理獲得的携御。
     */
    //Nullable-side端的"base rels"
    Relids      nullable_baserels;

    /*
     * join_rel_list is a list of all join-relation RelOptInfos we have
     * considered in this planning run.  For small problems we just scan the
     * list to do lookups, but when there are many join relations we build a
     * hash table for faster lookups.  The hash table is present and valid
     * when join_rel_hash is not NULL.  Note that we still maintain the list
     * even when using the hash table for lookups; this simplifies life for
     * GEQO.
     * join_rel_list是在計(jì)劃執(zhí)行中考慮的所有連接關(guān)系RelOptInfos的鏈表昌粤。
     * 對(duì)于小問(wèn)題既绕,只需要掃描鏈表執(zhí)行查找,但是當(dāng)存在許多連接關(guān)系時(shí)涮坐,
     *    需要構(gòu)建一個(gè)散列表來(lái)進(jìn)行更快的查找凄贩。
     * 當(dāng)join_rel_hash不為空時(shí),哈希表是有效可用于查詢(xún)的袱讹。
     * 注意疲扎,即使在使用哈希表進(jìn)行查找時(shí),仍然維護(hù)該鏈表;這簡(jiǎn)化了GEQO(遺傳算法)的生命周期捷雕。
     */
    //參與連接的Relation的RelOptInfo鏈表
    List       *join_rel_list;  /* list of join-relation RelOptInfos */
    //可加快鏈表訪問(wèn)的hash表
    struct HTAB *join_rel_hash; /* optional hashtable for join relations */

    /*
     * When doing a dynamic-programming-style join search, join_rel_level[k]
     * is a list of all join-relation RelOptInfos of level k, and
     * join_cur_level is the current level.  New join-relation RelOptInfos are
     * automatically added to the join_rel_level[join_cur_level] list.
     * join_rel_level is NULL if not in use.
     * 在執(zhí)行動(dòng)態(tài)規(guī)劃算法的連接搜索時(shí)椒丧,join_rel_level[k]是k級(jí)的所有連接關(guān)系RelOptInfos的列表,
     * join_cur_level是當(dāng)前級(jí)別救巷。
     * 新的連接關(guān)系RelOptInfos會(huì)自動(dòng)添加到j(luò)oin_rel_level[join_cur_level]鏈表中壶熏。
     * 如果不使用join_rel_level,則為NULL浦译。
     */
    //RelOptInfo指針鏈表數(shù)組,k層的join存儲(chǔ)在[k]中
    List      **join_rel_level; /* lists of join-relation RelOptInfos */
    //當(dāng)前的join層次
    int         join_cur_level; /* index of list being extended */
    //查詢(xún)的初始化計(jì)劃鏈表
    List       *init_plans;     /* init SubPlans for query */
    //CTE子計(jì)劃ID鏈表
    List       *cte_plan_ids;   /* per-CTE-item list of subplan IDs */
    //MULTIEXPR子查詢(xún)輸出的參數(shù)鏈表的鏈表
    List       *multiexpr_params;   /* List of Lists of Params for MULTIEXPR
                                     * subquery outputs */
    //活動(dòng)的等價(jià)類(lèi)鏈表
    List       *eq_classes;     /* list of active EquivalenceClasses */
    //規(guī)范化的PathKey鏈表
    List       *canon_pathkeys; /* list of "canonical" PathKeys */
    //外連接約束條件鏈表(左)
    List       *left_join_clauses;  /* list of RestrictInfos for mergejoinable
                                     * outer join clauses w/nonnullable var on
                                     * left */
    //外連接約束條件鏈表(右)
    List       *right_join_clauses; /* list of RestrictInfos for mergejoinable
                                     * outer join clauses w/nonnullable var on
                                     * right */
    //全連接約束條件鏈表
    List       *full_join_clauses;  /* list of RestrictInfos for mergejoinable
                                     * full join clauses */
    //特殊連接信息鏈表
    List       *join_info_list; /* list of SpecialJoinInfos */
    //AppendRelInfo鏈表
    List       *append_rel_list;    /* list of AppendRelInfos */
    //PlanRowMarks鏈表
    List       *rowMarks;       /* list of PlanRowMarks */
    //PHI鏈表
    List       *placeholder_list;   /* list of PlaceHolderInfos */
    // 外鍵信息鏈表
    List       *fkey_list;      /* list of ForeignKeyOptInfos */
    //query_planner()要求的PathKeys鏈表
    List       *query_pathkeys; /* desired pathkeys for query_planner() */
    //分組子句路徑鍵
    List       *group_pathkeys; /* groupClause pathkeys, if any */
    //窗口函數(shù)路徑鍵
    List       *window_pathkeys;    /* pathkeys of bottom window, if any */
    //distinctClause路徑鍵
    List       *distinct_pathkeys;  /* distinctClause pathkeys, if any */
    //排序路徑鍵
    List       *sort_pathkeys;  /* sortClause pathkeys, if any */
    //已規(guī)范化的分區(qū)Schema
    List       *part_schemes;   /* Canonicalised partition schemes used in the
                                 * query. */
    //嘗試連接的RelOptInfo鏈表
    List       *initial_rels;   /* RelOptInfos we are now trying to join */

    /* Use fetch_upper_rel() to get any particular upper rel */
    //上層的RelOptInfo鏈表
    List       *upper_rels[UPPERREL_FINAL + 1]; /*  upper-rel RelOptInfos */

    /* Result tlists chosen by grouping_planner for upper-stage processing */
    //grouping_planner為上層處理選擇的結(jié)果tlists
    struct PathTarget *upper_targets[UPPERREL_FINAL + 1];//

    /*
     * grouping_planner passes back its final processed targetlist here, for
     * use in relabeling the topmost tlist of the finished Plan.
     * grouping_planner在這里傳回它最終處理過(guò)的targetlist棒假,用于重新標(biāo)記已完成計(jì)劃的最頂層tlist。
     */
    ////最后需處理的投影列
    List       *processed_tlist;

    /* Fields filled during create_plan() for use in setrefs.c */
    //setrefs.c中在create_plan()函數(shù)調(diào)用期間填充的字段
    //分組函數(shù)屬性映射
    AttrNumber *grouping_map;   /* for GroupingFunc fixup */
    //MinMaxAggInfos鏈表
    List       *minmax_aggs;    /* List of MinMaxAggInfos */
    //內(nèi)存上下文
    MemoryContext planner_cxt;  /* context holding PlannerInfo */
    //關(guān)系的page計(jì)數(shù)
    double      total_table_pages;  /* # of pages in all tables of query */
    //query_planner輸入?yún)?shù):元組處理比例
    double      tuple_fraction; /* tuple_fraction passed to query_planner */
    //query_planner輸入?yún)?shù):limit_tuple
    double      limit_tuples;   /* limit_tuples passed to query_planner */
    //表達(dá)式的最小安全等級(jí)
    Index       qual_security_level;    /* minimum security_level for quals */
    /* Note: qual_security_level is zero if there are no securityQuals */
    //注意:如果沒(méi)有securityQuals, 則qual_security_level是NULL(0)

    //如目標(biāo)relation是分區(qū)表的child/partition/分區(qū)表,則通過(guò)此字段標(biāo)記
    InheritanceKind inhTargetKind;  /* indicates if the target relation is an
                                     * inheritance child or partition or a
                                     * partitioned table */
    //是否存在RTE_JOIN的RTE
    bool        hasJoinRTEs;    /* true if any RTEs are RTE_JOIN kind */
    //是否存在標(biāo)記為L(zhǎng)ATERAL的RTE
    bool        hasLateralRTEs; /* true if any RTEs are marked LATERAL */
    //是否存在已在jointree刪除的RTE
    bool        hasDeletedRTEs; /* true if any RTE was deleted from jointree */
    //是否存在Having子句
    bool        hasHavingQual;  /* true if havingQual was non-null */
    //如約束條件中存在pseudoconstant = true,則此字段為T(mén)
    bool        hasPseudoConstantQuals; /* true if any RestrictInfo has
                                         * pseudoconstant = true */
    //是否存在遞歸語(yǔ)句
    bool        hasRecursion;   /* true if planning a recursive WITH item */

    /* These fields are used only when hasRecursion is true: */
    //這些字段僅在hasRecursion為T(mén)時(shí)使用:
    //工作表的PARAM_EXEC ID
    int         wt_param_id;    /* PARAM_EXEC ID for the work table */
    //非遞歸模式的訪問(wèn)路徑
    struct Path *non_recursive_path;    /* a path for non-recursive term */

    /* These fields are workspace for createplan.c */
    //這些字段用于createplan.c
    //當(dāng)前節(jié)點(diǎn)之上的外部rels
    Relids      curOuterRels;   /* outer rels above current node */
    //未賦值的NestLoopParams參數(shù)
    List       *curOuterParams; /* not-yet-assigned NestLoopParams */

    /* optional private data for join_search_hook, e.g., GEQO */
    //可選的join_search_hook私有數(shù)據(jù)精盅,例如GEQO
    void       *join_search_private;

    /* Does this query modify any partition key columns? */
    //該查詢(xún)是否更新分區(qū)鍵列?
    bool        partColsUpdated;
} PlannerInfo;

二帽哑、參考資料

Parallel Append implementation
Partition Elimination in PostgreSQL 11

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市叹俏,隨后出現(xiàn)的幾起案子妻枕,更是在濱河造成了極大的恐慌,老刑警劉巖她肯,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件佳头,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡晴氨,警方通過(guò)查閱死者的電腦和手機(jī)康嘉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)籽前,“玉大人亭珍,你說(shuō)我怎么就攤上這事≈澹” “怎么了肄梨?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)挠锥。 經(jīng)常有香客問(wèn)我众羡,道長(zhǎng),這世上最難降的妖魔是什么蓖租? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任粱侣,我火速辦了婚禮羊壹,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘齐婴。我一直安慰自己油猫,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布柠偶。 她就那樣靜靜地躺著情妖,像睡著了一般。 火紅的嫁衣襯著肌膚如雪诱担。 梳的紋絲不亂的頭發(fā)上毡证,一...
    開(kāi)封第一講書(shū)人閱讀 51,624評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音该肴,去河邊找鬼情竹。 笑死,一個(gè)胖子當(dāng)著我的面吹牛匀哄,可吹牛的內(nèi)容都是我干的秦效。 我是一名探鬼主播,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼涎嚼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼阱州!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起法梯,我...
    開(kāi)封第一講書(shū)人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤苔货,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后立哑,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體夜惭,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年铛绰,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了诈茧。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡捂掰,死狀恐怖敢会,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情这嚣,我是刑警寧澤鸥昏,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站姐帚,受9級(jí)特大地震影響吏垮,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一惫皱、第九天 我趴在偏房一處隱蔽的房頂上張望像樊。 院中可真熱鬧,春花似錦旅敷、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至友酱,卻和暖如春晴音,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背缔杉。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工锤躁, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人或详。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓系羞,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親霸琴。 傳聞我的和親對(duì)象是個(gè)殘疾皇子椒振,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容