博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
PostgreSQL 源码解读(46)- 查询语句#31(query_planner函数#7)
阅读量:2499 次
发布时间:2019-05-11

本文共 27663 字,大约阅读时间需要 92 分钟。

先前的章节已介绍了函数query_planner中子函数reconsider_outer_join_clauses和generate_base_implied_equalities的主要实现逻辑,本节继续介绍query_planner中qp_callback(回调函数)、fix_placeholder_input_needed_levels函数的实现逻辑。

query_planner代码片段:

//...     /*      * We have completed merging equivalence sets, so it's now possible to      * generate pathkeys in canonical form; so compute query_pathkeys and      * other pathkeys fields in PlannerInfo.      */     (*qp_callback) (root, qp_extra);//调用回调函数,处理PathKeys      /*      * Examine any "placeholder" expressions generated during subquery pullup.      * Make sure that the Vars they need are marked as needed at the relevant      * join level.  This must be done before join removal because it might      * cause Vars or placeholders to be needed above a join when they weren't      * so marked before.      */     fix_placeholder_input_needed_levels(root);//检查在子查询上拉时生成的PH表达式,确保Vars是OK的      //...

一、数据结构

PlannerInfo与RelOptInfo结构体贯彻逻辑优化和物理优化过程的始终.

PlannerInfo

/*----------  * PlannerInfo  *      Per-query information for planning/optimization  *  * 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.  *----------  */ struct AppendRelInfo;  typedef struct PlannerInfo {     NodeTag     type;//Node标识      Query      *parse;          /* 查询树,the Query being planned */      PlannerGlobal *glob;        /* 当前的planner全局信息,global info for current planner run */      Index       query_level;    /* 查询层次,1标识最高层,1 at the outermost Query */      struct PlannerInfo *parent_root;    /* 如为子计划,则这里存储父计划器指针,NULL标识最高层,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.      */     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.      */     /* RelOptInfo数组,存储"base rels",比如基表/子查询等.该数组与RTE的顺序一一对应,而且是从1开始,因此[0]无用 */     struct RelOptInfo **simple_rel_array;   /* All 1-rel RelOptInfos */     int         simple_rel_array_size;  /* 数组大小,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.      */     RangeTblEntry **simple_rte_array;   /* RTE数组,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.      */     struct AppendRelInfo **append_rel_array;//先前已介绍,在处理集合操作如UNION ALL时使用      /*      * 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.      */     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.      */     Relids      nullable_baserels;//Nullable-side端的"base rels"      /*      * 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.      */     List       *join_rel_list;  /* 参与连接的Relation的RelOptInfo链表,list of join-relation RelOptInfos */     struct HTAB *join_rel_hash; /* 可加快链表访问的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.      */     List      **join_rel_level; /* RelOptInfo指针链表数组,k层的join存储在[k]中,lists of join-relation RelOptInfos */     int         join_cur_level; /* 当前的join层次,index of list being extended */      List       *init_plans;     /* 查询的初始化计划链表,init SubPlans for query */      List       *cte_plan_ids;   /* CTE子计划ID链表,per-CTE-item list of subplan IDs */      List       *multiexpr_params;   /* List of Lists of Params for MULTIEXPR                                      * subquery outputs */      List       *eq_classes;     /* 活动的等价类链表,list of active EquivalenceClasses */      List       *canon_pathkeys; /* 规范化PathKey链表,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 */      List       *append_rel_list;    /* AppendRelInfo链表,list of AppendRelInfos */      List       *rowMarks;       /* list of PlanRowMarks */      List       *placeholder_list;   /* PHI链表,list of PlaceHolderInfos */      List       *fkey_list;      /* 外键信息链表,list of ForeignKeyOptInfos */      List       *query_pathkeys; /* uery_planner()要求的PathKeys,desired pathkeys for query_planner() */      List       *group_pathkeys; /* groupClause pathkeys, if any */     List       *window_pathkeys;    /* pathkeys of bottom window, if any */     List       *distinct_pathkeys;  /* distinctClause pathkeys, if any */     List       *sort_pathkeys;  /* sortClause pathkeys, if any */      List       *part_schemes;   /* 已规范化的分区Schema,Canonicalised partition schemes used in the                                  * query. */      List       *initial_rels;   /* 尝试连接的RelOptInfo链表,RelOptInfos we are now trying to join */      /* Use fetch_upper_rel() to get any particular upper rel */     List       *upper_rels[UPPERREL_FINAL + 1]; /* 上层的RelOptInfo链表, upper-rel RelOptInfos */      /* Result tlists chosen by grouping_planner for upper-stage processing */     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.      */     List       *processed_tlist;//最后需处理的投影列      /* Fields filled during create_plan() for use in setrefs.c */     AttrNumber *grouping_map;   /* for GroupingFunc fixup */     List       *minmax_aggs;    /* List of MinMaxAggInfos */      MemoryContext planner_cxt;  /* 内存上下文,context holding PlannerInfo */      double      total_table_pages;  /* 所有的pages,# of pages in all tables of query */      double      tuple_fraction; /* query_planner输入参数:元组处理比例,tuple_fraction passed to query_planner */     double      limit_tuples;   /* query_planner输入参数:limit_tuples passed to query_planner */      Index       qual_security_level;    /* 表达式的最新安全等级,minimum security_level for quals */     /* Note: qual_security_level is zero if there are no securityQuals */      InheritanceKind inhTargetKind;  /* indicates if the target relation is an                                      * inheritance child or partition or a                                      * partitioned table */     bool        hasJoinRTEs;    /* 存在RTE_JOIN的RTE,true if any RTEs are RTE_JOIN kind */     bool        hasLateralRTEs; /* 存在标记为LATERAL的RTE,true if any RTEs are marked LATERAL */     bool        hasDeletedRTEs; /* 存在已在jointree删除的RTE,true if any RTE was deleted from jointree */     bool        hasHavingQual;  /* 存在Having子句,true if havingQual was non-null */     bool        hasPseudoConstantQuals; /* true if any RestrictInfo has                                          * pseudoconstant = true */     bool        hasRecursion;   /* 递归语句,true if planning a recursive WITH item */      /* These fields are used only when hasRecursion is true: */     int         wt_param_id;    /* PARAM_EXEC ID for the work table */     struct Path *non_recursive_path;    /* a path for non-recursive term */      /* These fields are workspace for createplan.c */     Relids      curOuterRels;   /* outer rels above current node */     List       *curOuterParams; /* not-yet-assigned NestLoopParams */      /* optional private data for join_search_hook, e.g., GEQO */     void       *join_search_private;      /* Does this query modify any partition key columns? */     bool        partColsUpdated; } PlannerInfo;

RelOptInfo

typedef struct RelOptInfo {     NodeTag     type;//节点标识      RelOptKind  reloptkind;//RelOpt类型      /* all relations included in this RelOptInfo */     Relids      relids;         /*Relids(rtindex)集合 set of base relids (rangetable indexes) */      /* size estimates generated by planner */     double      rows;           /*结果元组的估算数量 estimated number of result tuples */      /* per-relation planner control flags */     bool        consider_startup;   /*是否考虑启动成本?是,需要保留启动成本低的路径 keep cheap-startup-cost paths? */     bool        consider_param_startup; /*是否考虑参数化?的路径 ditto, for parameterized paths? */     bool        consider_parallel;  /*是否考虑并行处理路径 consider parallel paths? */      /* default result targetlist for Paths scanning this relation */     struct PathTarget *reltarget;   /*扫描该Relation时默认的结果 list of Vars/Exprs, cost, width */      /* materialization information */     List       *pathlist;       /*访问路径链表 Path structures */     List       *ppilist;        /*路径链表中使用参数化路径进行 ParamPathInfos used in pathlist */     List       *partial_pathlist;   /* partial Paths */     struct Path *cheapest_startup_path;//代价最低的启动路径     struct Path *cheapest_total_path;//代价最低的整体路径     struct Path *cheapest_unique_path;//代价最低的获取唯一值的路径     List       *cheapest_parameterized_paths;//代价最低的参数化?路径链表      /* parameterization information needed for both base rels and join rels */     /* (see also lateral_vars and lateral_referencers) */     Relids      direct_lateral_relids;  /*使用lateral语法,需依赖的Relids rels directly laterally referenced */     Relids      lateral_relids; /* minimum parameterization of rel */      /* information about a base rel (not set for join rels!) */     //reloptkind=RELOPT_BASEREL时使用的数据结构     Index       relid;          /* Relation ID */     Oid         reltablespace;  /* 表空间 containing tablespace */     RTEKind     rtekind;        /* 基表?子查询?还是函数等等?RELATION, SUBQUERY, FUNCTION, etc */     AttrNumber  min_attr;       /* 最小的属性编号 smallest attrno of rel (often <0) */     AttrNumber  max_attr;       /* 最大的属性编号 largest attrno of rel */     Relids     *attr_needed;    /* 数组 array indexed [min_attr .. max_attr] */     int32      *attr_widths;    /* 属性宽度 array indexed [min_attr .. max_attr] */     List       *lateral_vars;   /* 关系依赖的Vars/PHVs LATERAL Vars and PHVs referenced by rel */     Relids      lateral_referencers;    /*依赖该关系的Relids rels that reference me laterally */     List       *indexlist;      /* 该关系的IndexOptInfo链表 list of IndexOptInfo */     List       *statlist;       /* 统计信息链表 list of StatisticExtInfo */     BlockNumber pages;          /* 块数 size estimates derived from pg_class */     double      tuples;         /* 元组数 */     double      allvisfrac;     /* ? */     PlannerInfo *subroot;       /* 如为子查询,存储子查询的root if subquery */     List       *subplan_params; /* 如为子查询,存储子查询的参数 if subquery */     int         rel_parallel_workers;   /* 并行执行,需要多少个workers? wanted number of parallel workers */      /* Information about foreign tables and foreign joins */     //FWD相关信息     Oid         serverid;       /* identifies server for the table or join */     Oid         userid;         /* identifies user to check access as */     bool        useridiscurrent;    /* join is only valid for current user */     /* use "struct FdwRoutine" to avoid including fdwapi.h here */     struct FdwRoutine *fdwroutine;     void       *fdw_private;      /* cache space for remembering if we have proven this relation unique */     //已知的,可保证唯一的Relids链表     List       *unique_for_rels;    /* known unique for these other relid                                      * set(s) */     List       *non_unique_for_rels;    /* 已知的,不唯一的Relids链表 known not unique for these set(s) */      /* used by various scans and joins: */     List       *baserestrictinfo;   /* 如为基本关系,存储约束条件 RestrictInfo structures (if base rel) */     QualCost    baserestrictcost;   /* 解析约束表达式的成本? cost of evaluating the above */     Index       baserestrict_min_security;  /* 最低安全等级 min security_level found in                                              * baserestrictinfo */     List       *joininfo;       /* 连接语句的约束条件信息 RestrictInfo structures for join clauses                                  * involving this rel */     bool        has_eclass_joins;   /* 是否存在等价类连接? T means joininfo is incomplete */      /* used by partitionwise joins: */     bool        consider_partitionwise_join;    /* 分区? consider partitionwise                                                  * join paths? (if                                                  * partitioned rel) */     Relids      top_parent_relids;  /* Relids of topmost parents (if "other"                                      * rel) */      /* used for partitioned relations */     //分区表使用     PartitionScheme part_scheme;    /* 分区的schema Partitioning scheme. */     int         nparts;         /* 分区数 number of partitions */     struct PartitionBoundInfoData *boundinfo;   /* 分区边界信息 Partition bounds */     List       *partition_qual; /* 分区约束 partition constraint */     struct RelOptInfo **part_rels;  /* 分区的RelOptInfo数组 Array of RelOptInfos of partitions,                                      * stored in the same order of bounds */     List      **partexprs;      /* 非空分区键表达式 Non-nullable partition key expressions. */     List      **nullable_partexprs; /* 可为空的分区键表达式 Nullable partition key expressions. */     List       *partitioned_child_rels; /* RT Indexes链表 List of RT indexes. */ } RelOptInfo;

PlaceHolderInfo

/*  * For each distinct placeholder expression generated during planning, we  * store a PlaceHolderInfo node in the PlannerInfo node's placeholder_list.  * This stores info that is needed centrally rather than in each copy of the  * PlaceHolderVar.  The phid fields identify which PlaceHolderInfo goes with  * each PlaceHolderVar.  Note that phid is unique throughout a planner run,  * not just within a query level --- this is so that we need not reassign ID's  * when pulling a subquery into its parent.  *  * The idea is to evaluate the expression at (only) the ph_eval_at join level,  * then allow it to bubble up like a Var until the ph_needed join level.  * ph_needed has the same definition as attr_needed for a regular Var.  *  * The PlaceHolderVar's expression might contain LATERAL references to vars  * coming from outside its syntactic scope.  If so, those rels are *not*  * included in ph_eval_at, but they are recorded in ph_lateral.  *  * Notice that when ph_eval_at is a join rather than a single baserel, the  * PlaceHolderInfo may create constraints on join order: the ph_eval_at join  * has to be formed below any outer joins that should null the PlaceHolderVar.  *  * We create a PlaceHolderInfo only after determining that the PlaceHolderVar  * is actually referenced in the plan tree, so that unreferenced placeholders  * don't result in unnecessary constraints on join order.  */  typedef struct PlaceHolderInfo {     NodeTag     type;      Index       phid;           /* PH的ID,ID for PH (unique within planner run) */     PlaceHolderVar *ph_var;     /* copy of PlaceHolderVar tree */     Relids      ph_eval_at;     /* lowest level we can evaluate value at */     Relids      ph_lateral;     /* relids of contained lateral refs, if any */     Relids      ph_needed;      /* highest level the value is needed at */     int32       ph_width;       /* estimated attribute width */ } PlaceHolderInfo;

二、源码解读

standard_qp_callback

标准的query_planner回调函数,在生成计划的期间处理query_pathkeys和其他pathkeys

/*  * Compute query_pathkeys and other pathkeys during plan generation  */ static void standard_qp_callback(PlannerInfo *root, void *extra) {     Query      *parse = root->parse;//查询树     standard_qp_extra *qp_extra = (standard_qp_extra *) extra;//参数     List       *tlist = qp_extra->tlist;     List       *activeWindows = qp_extra->activeWindows;      /*      * Calculate pathkeys that represent grouping/ordering requirements.  The      * sortClause is certainly sort-able, but GROUP BY and DISTINCT might not      * be, in which case we just leave their pathkeys empty.      */     if (qp_extra->groupClause &&         grouping_is_sortable(qp_extra->groupClause))//group语句&要求排序         root->group_pathkeys =             make_pathkeys_for_sortclauses(root,                                           qp_extra->groupClause,                                           tlist);//构建pathkeys     else         root->group_pathkeys = NIL;      /* We consider only the first (bottom) window in pathkeys logic */     if (activeWindows != NIL)//窗口函数     {         WindowClause *wc = linitial_node(WindowClause, activeWindows);          root->window_pathkeys = make_pathkeys_for_window(root,                                                          wc,                                                          tlist);     }     else         root->window_pathkeys = NIL;      if (parse->distinctClause &&         grouping_is_sortable(parse->distinctClause))//存在distinct语句&按相关字段排序         root->distinct_pathkeys =             make_pathkeys_for_sortclauses(root,                                           parse->distinctClause,                                           tlist);//构建pathkeys     else         root->distinct_pathkeys = NIL;      root->sort_pathkeys =         make_pathkeys_for_sortclauses(root,                                       parse->sortClause,                                       tlist);//构建常规的排序pathkeys      /*      * Figure out whether we want a sorted result from query_planner.      *      * If we have a sortable GROUP BY clause, then we want a result sorted      * properly for grouping.  Otherwise, if we have window functions to      * evaluate, we try to sort for the first window.  Otherwise, if there's a      * sortable DISTINCT clause that's more rigorous than the ORDER BY clause,      * we try to produce output that's sufficiently well sorted for the      * DISTINCT.  Otherwise, if there is an ORDER BY clause, we want to sort      * by the ORDER BY clause.      *      * Note: if we have both ORDER BY and GROUP BY, and ORDER BY is a superset      * of GROUP BY, it would be tempting to request sort by ORDER BY --- but      * that might just leave us failing to exploit an available sort order at      * all.  Needs more thought.  The choice for DISTINCT versus ORDER BY is      * much easier, since we know that the parser ensured that one is a      * superset of the other.      */     if (root->groupremove_useless_joins_pathkeys)         root->query_pathkeys = root->group_pathkeys;     else if (root->window_pathkeys)         root->query_pathkeys = root->window_pathkeys;     else if (list_length(root->distinct_pathkeys) >              list_length(root->sort_pathkeys))         root->query_pathkeys = root->distinct_pathkeys;     else if (root->sort_pathkeys)         root->query_pathkeys = root->sort_pathkeys;     else         root->query_pathkeys = NIL; }/*  * make_pathkeys_for_sortclauses  *      Generate a pathkeys list that represents the sort order specified  *      by a list of SortGroupClauses  *  * The resulting PathKeys are always in canonical form.  (Actually, there  * is no longer any code anywhere that creates non-canonical PathKeys.)  *  * We assume that root->nullable_baserels is the set of base relids that could  * have gone to NULL below the SortGroupClause expressions.  This is okay if  * the expressions came from the query's top level (ORDER BY, DISTINCT, etc)  * and if this function is only invoked after deconstruct_jointree.  In the  * future we might have to make callers pass in the appropriate  * nullable-relids set, but for now it seems unnecessary.  *  * 'sortclauses' is a list of SortGroupClause nodes  * 'tlist' is the targetlist to find the referenced tlist entries in  */ List * make_pathkeys_for_sortclauses(PlannerInfo *root,                               List *sortclauses,                               List *tlist) {     List       *pathkeys = NIL;     ListCell   *l;      foreach(l, sortclauses)     {         SortGroupClause *sortcl = (SortGroupClause *) lfirst(l);         Expr       *sortkey;         PathKey    *pathkey;          sortkey = (Expr *) get_sortgroupclause_expr(sortcl, tlist);         Assert(OidIsValid(sortcl->sortop));         pathkey = make_pathkey_from_sortop(root,                                            sortkey,                                            root->nullable_baserels,                                            sortcl->sortop,                                            sortcl->nulls_first,                                            sortcl->tleSortGroupRef,                                            true);          /* Canonical form eliminates redundant ordering keys */         if (!pathkey_is_redundant(pathkey, pathkeys))//不是多余的Key的情况下,才保留             pathkeys = lappend(pathkeys, pathkey);     }     return pathkeys; }

测试脚本:

testdb=# select t1.dwbh,t2.grbhfrom t_dwxx t1 left join t_grxx t2 on t1.dwbh = t2.dwbhwhere t1.dwbh = '1001'order by t1.dwbh;

跟踪分析,进入make_pathkeys_for_sortclauses函数:

...(gdb) stepmake_pathkeys_for_sortclauses (root=0x1702958, sortclauses=0x170d068, tlist=0x1746758) at pathkeys.c:878878   List     *pathkeys = NIL;(gdb) p *(SortGroupClause *)sortclauses->head->data.ptr_value$5 = {type = T_SortGroupClause, tleSortGroupRef = 1, eqop = 98, sortop = 664, nulls_first = false, hashable = true}...(gdb) n889     pathkey = make_pathkey_from_sortop(root,(gdb) 898     if (!pathkey_is_redundant(pathkey, pathkeys))(gdb) p *pathkey$11 = {type = T_PathKey, pk_eclass = 0x17486c0, pk_opfamily = 1994, pk_strategy = 1, pk_nulls_first = false}

函数pathkey_is_redundant通过等价类判断排序是否多余(redundant),在本例中,已存在限制条件dwbh='1001',因此该排序是多余的,返回NULL.

901   return pathkeys;(gdb) p *pathkeysCannot access memory at address 0x0

fix_placeholder_input_needed_levels

/*  * fix_placeholder_input_needed_levels  *      Adjust the "needed at" levels for placeholder inputs  *  * This is called after we've finished determining the eval_at levels for  * all placeholders.  We need to make sure that all vars and placeholders  * needed to evaluate each placeholder will be available at the scan or join  * level where the evaluation will be done.  (It might seem that scan-level  * evaluations aren't interesting, but that's not so: a LATERAL reference  * within a placeholder's expression needs to cause the referenced var or  * placeholder to be marked as needed in the scan where it's evaluated.)  * Note that this loop can have side-effects on the ph_needed sets of other  * PlaceHolderInfos; that's okay because we don't examine ph_needed here, so  * there are no ordering issues to worry about.  */ void fix_placeholder_input_needed_levels(PlannerInfo *root) {     ListCell   *lc;      foreach(lc, root->placeholder_list)//遍历链表     {         PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(lc);         List       *vars = pull_var_clause((Node *) phinfo->ph_var->phexpr,                                            PVC_RECURSE_AGGREGATES |                                            PVC_RECURSE_WINDOWFUNCS |                                            PVC_INCLUDE_PLACEHOLDERS);//获取Vars          add_vars_to_targetlist(root, vars, phinfo->ph_eval_at, false);//添加到投影列中         list_free(vars);     } }

考察下面的SQL语句:

testdb=# explain verbose select t1.dwbh,t2.grbh,t2.constant_fieldfrom t_dwxx t1 left join (select a.dwbh,a.grbh,'TEST' as constant_field from t_grxx a) t2 on t1.dwbh = t2.dwbh  where t1.dwbh = '1001'order by t1.dwbh;                               QUERY PLAN                               ------------------------------------------------------------------------ Nested Loop Left Join  (cost=0.00..16.06 rows=2 width=108)   Output: t1.dwbh, a.grbh, ('TEST'::text) -- PlaceHolderVar   Join Filter: ((t1.dwbh)::text = (a.dwbh)::text)   ->  Seq Scan on public.t_dwxx t1  (cost=0.00..1.04 rows=1 width=38)         Output: t1.dwmc, t1.dwbh, t1.dwdz         Filter: ((t1.dwbh)::text = '1001'::text)   ->  Seq Scan on public.t_grxx a  (cost=0.00..15.00 rows=2 width=108)         Output: a.grbh, a.dwbh, 'TEST'::text         Filter: ((a.dwbh)::text = '1001'::text)(9 rows)

子查询上拉与t_dwxx进行连接,上拉过程中,不能简单的把子查询中的"'TEST' as constant_field"作为上层查询的Var来看待(如果不作特殊处理,跟外连接就不等价了,因为该值有可能是NULL),PG因此引入了PlaceHolderVar这么一个Var来对这种变量进行特殊处理.

跟踪分析:

(gdb) b planmain.c:161Breakpoint 1 at 0x769602: file planmain.c, line 161.(gdb) cContinuing.Breakpoint 1, query_planner (root=0x1702b08, tlist=0x1749c20, qp_callback=0x76e97d 
, qp_extra=0x7ffd35e059c0) at planmain.c:163163 reconsider_outer_join_clauses(root);

注意root中的placeholder_list

(gdb) p *root$1 = {type = T_PlannerInfo, ..., placeholder_list = 0x174bf00, ...}

查看其内存结构:

#1个PHV(gdb) p *root->placeholder_list$2 = {type = T_List, length = 1, head = 0x174bee0, tail = 0x174bee0}(gdb) p *(Node *)root->placeholder_list->head->data.ptr_value$3 = {type = T_PlaceHolderInfo}(gdb) p *(PlaceHolderInfo *)root->placeholder_list->head->data.ptr_value$4 = {type = T_PlaceHolderInfo, phid = 1, ph_var = 0x174be18, ph_eval_at = 0x174bec8, ph_lateral = 0x0,   ph_needed = 0x174bf30, ph_width = 32}(gdb) set $phi=(PlaceHolderInfo *)root->placeholder_list->head->data.ptr_value(gdb) p *$phi->ph_var$5 = {xpr = {type = T_PlaceHolderVar}, phexpr = 0x174be48, phrels = 0x174beb0, phid = 1, phlevelsup = 0}#该PHV位于编号为4的RTE中(gdb) p *$phi->ph_eval_at$6 = {nwords = 1, words = 0x174becc}(gdb) p *$phi->ph_eval_at->words$7 = 16(gdb) p *$phi->ph_needed$8 = {nwords = 1, words = 0x174bf34}#该PHV在编号为1的RTE中需要用到(gdb) p *$phi->ph_needed->words$9 = 1

三、参考资料

planmain.c

what exactly is a PlaceHolderVAr

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/6906/viewspace-2374865/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/6906/viewspace-2374865/

你可能感兴趣的文章
期货市场技术分析02_趋势的基本概念
查看>>
期货市场技术分析03_主要反转形态
查看>>
期货市场技术分析04_持续形态
查看>>
期货市场技术分析05_交易量和持仓兴趣
查看>>
TB交易开拓者入门教程
查看>>
TB创建公式应用dll失败 请检查用户权限,终极解决方案
查看>>
python绘制k线图(蜡烛图)报错 No module named 'matplotlib.finance
查看>>
talib均线大全
查看>>
期货市场技术分析06_长期图表和商品指数
查看>>
期货市场技术分析07_摆动指数和相反意见理论
查看>>
满屏的指标?删了吧,手把手教你裸 K 交易!
查看>>
不吹不黑 | 聊聊为什么要用99%精度的数据回测
查看>>
高频交易的几种策略
查看>>
量化策略回测TRIXKDJ
查看>>
量化策略回测唐安奇通道
查看>>
CTA策略如何过滤部分震荡行情?
查看>>
量化策略回测DualThrust
查看>>
量化策略回测BoolC
查看>>
量化策略回测DCCV2
查看>>
mongodb查询优化
查看>>