PostgreSQL查询优化中如何实现上拉子链接

发布时间:2021-11-11 11:29:48 作者:iii
来源:亿速云 阅读:245

本篇内容介绍了“PostgreSQL查询优化中如何实现上拉子链接”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

查询树

 /*
  * Recurse through jointree nodes for pull_up_sublinks()
  *
  * In addition to returning the possibly-modified jointree node, we return
  * a relids set of the contained rels into *relids.
  */
 static Node *
 pull_up_sublinks_jointree_recurse(PlannerInfo *root, Node *jtnode,
                                   Relids *relids)
 {
     if (jtnode == NULL)
     {
         *relids = NULL;
     }
     else if (IsA(jtnode, RangeTblRef))//如为RangeTblRef类型
     {
         int         varno = ((RangeTblRef *) jtnode)->rtindex;
 
         *relids = bms_make_singleton(varno);
         /* jtnode is returned unmodified */
     }
     else if (IsA(jtnode, FromExpr))//如为FromExpr类型
     {
         FromExpr   *f = (FromExpr *) jtnode;
         List       *newfromlist = NIL;
         Relids      frelids = NULL;
         FromExpr   *newf;
         Node       *jtlink;
         ListCell   *l;
 
         /* First, recurse to process children and collect their relids */
         foreach(l, f->fromlist)//
         {
             Node       *newchild;
             Relids      childrelids;
             //对fromlist中的元素执行上拉操作
             //如能够上拉,则把子查询从WHERE子句中提升到FROM子句,newchild作为连接的一部分
             newchild = pull_up_sublinks_jointree_recurse(root,
                                                          lfirst(l),
                                                          &childrelids);
             newfromlist = lappend(newfromlist, newchild);
             frelids = bms_join(frelids, childrelids);
         }
         /* Build the replacement FromExpr; no quals yet */
         newf = makeFromExpr(newfromlist, NULL);//创建新的FromExpr
         /* Set up a link representing the rebuilt jointree */
         jtlink = (Node *) newf;
         /* Now process qual --- all children are available for use */
         //处理子链接中的表达式
         //newf(指针,相当于jtlink)
         newf->quals = pull_up_sublinks_qual_recurse(root, f->quals,
                                                     &jtlink, frelids,
                                                     NULL, NULL);//
 
         /*
          * Note that the result will be either newf, or a stack of JoinExprs
          * with newf at the base.  We rely on subsequent optimization steps to
          * flatten this and rearrange the joins as needed.
          *
          * Although we could include the pulled-up subqueries in the returned
          * relids, there's no need since upper quals couldn't refer to their
          * outputs anyway.
          */
         *relids = frelids;//设置相关的relids
         jtnode = jtlink;//返回值
     }
     else if (IsA(jtnode, JoinExpr))
     {
         JoinExpr   *j;
         Relids      leftrelids;
         Relids      rightrelids;
         Node       *jtlink;
 
         /*
          * Make a modifiable copy of join node, but don't bother copying its
          * subnodes (yet).
          */
         j = (JoinExpr *) palloc(sizeof(JoinExpr));
         memcpy(j, jtnode, sizeof(JoinExpr));
         jtlink = (Node *) j;
 
         /* Recurse to process children and collect their relids */
         //递归处理左边&右边子树
         j->larg = pull_up_sublinks_jointree_recurse(root, j->larg,
                                                     &leftrelids);
         j->rarg = pull_up_sublinks_jointree_recurse(root, j->rarg,
                                                     &rightrelids);
 
         /*
          * Now process qual, showing appropriate child relids as available,
          * and attach any pulled-up jointree items at the right place. In the
          * inner-join case we put new JoinExprs above the existing one (much
          * as for a FromExpr-style join).  In outer-join cases the new
          * JoinExprs must go into the nullable side of the outer join. The
          * point of the available_rels machinations is to ensure that we only
          * pull up quals for which that's okay.
          *
          * We don't expect to see any pre-existing JOIN_SEMI or JOIN_ANTI
          * nodes here.
          */
         switch (j->jointype)
         {
             case JOIN_INNER:
                 j->quals = pull_up_sublinks_qual_recurse(root, j->quals,
                                                          &jtlink,
                                                          bms_union(leftrelids,
                                                                    rightrelids),
                                                          NULL, NULL);
                 break;
             case JOIN_LEFT:
                 j->quals = pull_up_sublinks_qual_recurse(root, j->quals,
                                                          &j->rarg,
                                                          rightrelids,
                                                          NULL, NULL);
                 break;
             case JOIN_FULL:
                 /* can't do anything with full-join quals */
                 break;
             case JOIN_RIGHT:
                 j->quals = pull_up_sublinks_qual_recurse(root, j->quals,
                                                          &j->larg,
                                                          leftrelids,
                                                          NULL, NULL);
                 break;
             default:
                 elog(ERROR, "unrecognized join type: %d",
                      (int) j->jointype);
                 break;
         }
 
         /*
          * Although we could include the pulled-up subqueries in the returned
          * relids, there's no need since upper quals couldn't refer to their
          * outputs anyway.  But we *do* need to include the join's own rtindex
          * because we haven't yet collapsed join alias variables, so upper
          * levels would mistakenly think they couldn't use references to this
          * join.
          */
         *relids = bms_join(leftrelids, rightrelids);
         if (j->rtindex)
             *relids = bms_add_member(*relids, j->rtindex);
         jtnode = jtlink;
     }
     else
         elog(ERROR, "unrecognized node type: %d",
              (int) nodeTag(jtnode));
     return jtnode;
 }

pull_up_sublinks_qual_recurse

 /*
  * Recurse through top-level qual nodes for pull_up_sublinks()
  *
  * jtlink1 points to the link in the jointree where any new JoinExprs should
  * be inserted if they reference available_rels1 (i.e., available_rels1
  * denotes the relations present underneath jtlink1).  Optionally, jtlink2 can
  * point to a second link where new JoinExprs should be inserted if they
  * reference available_rels2 (pass NULL for both those arguments if not used).
  * Note that SubLinks referencing both sets of variables cannot be optimized.
  * If we find multiple pull-up-able SubLinks, they'll get stacked onto jtlink1
  * and/or jtlink2 in the order we encounter them.  We rely on subsequent
  * optimization to rearrange the stack if appropriate.
  *
  * Returns the replacement qual node, or NULL if the qual should be removed.
  */
 static Node *
 pull_up_sublinks_qual_recurse(PlannerInfo *root, Node *node,
                               Node **jtlink1, Relids available_rels1,
                               Node **jtlink2, Relids available_rels2)
 {
     if (node == NULL)
         return NULL;
     if (IsA(node, SubLink))//子链接
     {
         SubLink    *sublink = (SubLink *) node;
         JoinExpr   *j;
         Relids      child_rels;
 
         /* Is it a convertible ANY or EXISTS clause? */
         if (sublink->subLinkType == ANY_SUBLINK)//ANY子链接
         {
             if ((j = convert_ANY_sublink_to_join(root, sublink,
                                                  available_rels1)) != NULL)
             {
                 /* Yes; insert the new join node into the join tree */
                 j->larg = *jtlink1;
                 *jtlink1 = (Node *) j;
                 /* Recursively process pulled-up jointree nodes */
                 j->rarg = pull_up_sublinks_jointree_recurse(root,
                                                             j->rarg,
                                                             &child_rels);
 
                 /*
                  * Now recursively process the pulled-up quals.  Any inserted
                  * joins can get stacked onto either j->larg or j->rarg,
                  * depending on which rels they reference.
                  */
                 j->quals = pull_up_sublinks_qual_recurse(root,
                                                          j->quals,
                                                          &j->larg,
                                                          available_rels1,
                                                          &j->rarg,
                                                          child_rels);
                 /* Return NULL representing constant TRUE */
                 return NULL;
             }
             if (available_rels2 != NULL &&
                 (j = convert_ANY_sublink_to_join(root, sublink,
                                                  available_rels2)) != NULL)
             {
                 /* Yes; insert the new join node into the join tree */
                 j->larg = *jtlink2;
                 *jtlink2 = (Node *) j;
                 /* Recursively process pulled-up jointree nodes */
                 j->rarg = pull_up_sublinks_jointree_recurse(root,
                                                             j->rarg,
                                                             &child_rels);
 
                 /*
                  * Now recursively process the pulled-up quals.  Any inserted
                  * joins can get stacked onto either j->larg or j->rarg,
                  * depending on which rels they reference.
                  */
                 j->quals = pull_up_sublinks_qual_recurse(root,
                                                          j->quals,
                                                          &j->larg,
                                                          available_rels2,
                                                          &j->rarg,
                                                          child_rels);
                 /* Return NULL representing constant TRUE */
                 return NULL;
             }
         }
         else if (sublink->subLinkType == EXISTS_SUBLINK)//EXISTS子链接
         {
             if ((j = convert_EXISTS_sublink_to_join(root, sublink, false,
                                                     available_rels1)) != NULL)
             {
                 /* Yes; insert the new join node into the join tree */
                 j->larg = *jtlink1;
                 *jtlink1 = (Node *) j;
                 /* Recursively process pulled-up jointree nodes */
                 j->rarg = pull_up_sublinks_jointree_recurse(root,
                                                             j->rarg,
                                                             &child_rels);
 
                 /*
                  * Now recursively process the pulled-up quals.  Any inserted
                  * joins can get stacked onto either j->larg or j->rarg,
                  * depending on which rels they reference.
                  */
                 j->quals = pull_up_sublinks_qual_recurse(root,
                                                          j->quals,
                                                          &j->larg,
                                                          available_rels1,
                                                          &j->rarg,
                                                          child_rels);
                 /* Return NULL representing constant TRUE */
                 return NULL;
             }
             if (available_rels2 != NULL &&
                 (j = convert_EXISTS_sublink_to_join(root, sublink, false,
                                                     available_rels2)) != NULL)
             {
                 /* Yes; insert the new join node into the join tree */
                 j->larg = *jtlink2;
                 *jtlink2 = (Node *) j;
                 /* Recursively process pulled-up jointree nodes */
                 j->rarg = pull_up_sublinks_jointree_recurse(root,
                                                             j->rarg,
                                                             &child_rels);
 
                 /*
                  * Now recursively process the pulled-up quals.  Any inserted
                  * joins can get stacked onto either j->larg or j->rarg,
                  * depending on which rels they reference.
                  */
                 j->quals = pull_up_sublinks_qual_recurse(root,
                                                          j->quals,
                                                          &j->larg,
                                                          available_rels2,
                                                          &j->rarg,
                                                          child_rels);
                 /* Return NULL representing constant TRUE */
                 return NULL;
             }
         }
         /* Else return it unmodified */
         return node;
     }
     if (not_clause(node))//NOT语句
     {
         /* If the immediate argument of NOT is EXISTS, try to convert */
         SubLink    *sublink = (SubLink *) get_notclausearg((Expr *) node);
         JoinExpr   *j;
         Relids      child_rels;
 
         if (sublink && IsA(sublink, SubLink))
         {
             if (sublink->subLinkType == EXISTS_SUBLINK)
             {
                 if ((j = convert_EXISTS_sublink_to_join(root, sublink, true,
                                                         available_rels1)) != NULL)
                 {
                     /* Yes; insert the new join node into the join tree */
                     j->larg = *jtlink1;
                     *jtlink1 = (Node *) j;
                     /* Recursively process pulled-up jointree nodes */
                     j->rarg = pull_up_sublinks_jointree_recurse(root,
                                                                 j->rarg,
                                                                 &child_rels);
 
                     /*
                      * Now recursively process the pulled-up quals.  Because
                      * we are underneath a NOT, we can't pull up sublinks that
                      * reference the left-hand stuff, but it's still okay to
                      * pull up sublinks referencing j->rarg.
                      */
                     j->quals = pull_up_sublinks_qual_recurse(root,
                                                              j->quals,
                                                              &j->rarg,
                                                              child_rels,
                                                              NULL, NULL);
                     /* Return NULL representing constant TRUE */
                     return NULL;
                 }
                 if (available_rels2 != NULL &&
                     (j = convert_EXISTS_sublink_to_join(root, sublink, true,
                                                         available_rels2)) != NULL)
                 {
                     /* Yes; insert the new join node into the join tree */
                     j->larg = *jtlink2;
                     *jtlink2 = (Node *) j;
                     /* Recursively process pulled-up jointree nodes */
                     j->rarg = pull_up_sublinks_jointree_recurse(root,
                                                                 j->rarg,
                                                                 &child_rels);
 
                     /*
                      * Now recursively process the pulled-up quals.  Because
                      * we are underneath a NOT, we can't pull up sublinks that
                      * reference the left-hand stuff, but it's still okay to
                      * pull up sublinks referencing j->rarg.
                      */
                     j->quals = pull_up_sublinks_qual_recurse(root,
                                                              j->quals,
                                                              &j->rarg,
                                                              child_rels,
                                                              NULL, NULL);
                     /* Return NULL representing constant TRUE */
                     return NULL;
                 }
             }
         }
         /* Else return it unmodified */
         return node;
     }
     if (and_clause(node))//AND语句
     {
         /* Recurse into AND clause */
         List       *newclauses = NIL;
         ListCell   *l;
 
         foreach(l, ((BoolExpr *) node)->args)
         {
             Node       *oldclause = (Node *) lfirst(l);
             Node       *newclause;
 
             newclause = pull_up_sublinks_qual_recurse(root,
                                                       oldclause,
                                                       jtlink1,
                                                       available_rels1,
                                                       jtlink2,
                                                       available_rels2);
             if (newclause)
                 newclauses = lappend(newclauses, newclause);
         }
         /* We might have got back fewer clauses than we started with */
         if (newclauses == NIL)
             return NULL;
         else if (list_length(newclauses) == 1)
             return (Node *) linitial(newclauses);
         else
             return (Node *) make_andclause(newclauses);
     }
     /* Stop if not an AND */
     return node;
 }

convert_ANY_sublink_to_join

 /*
  * convert_ANY_sublink_to_join: try to convert an ANY SubLink to a join
  *
  * The caller has found an ANY SubLink at the top level of one of the query's
  * qual clauses, but has not checked the properties of the SubLink further.
  * Decide whether it is appropriate to process this SubLink in join style.
  * If so, form a JoinExpr and return it.  Return NULL if the SubLink cannot
  * be converted to a join.
  *
  * The only non-obvious input parameter is available_rels: this is the set
  * of query rels that can safely be referenced in the sublink expression.
  * (We must restrict this to avoid changing the semantics when a sublink
  * is present in an outer join's ON qual.)  The conversion must fail if
  * the converted qual would reference any but these parent-query relids.
  *
  * On success, the returned JoinExpr has larg = NULL and rarg = the jointree
  * item representing the pulled-up subquery.  The caller must set larg to
  * represent the relation(s) on the lefthand side of the new join, and insert
  * the JoinExpr into the upper query's jointree at an appropriate place
  * (typically, where the lefthand relation(s) had been).  Note that the
  * passed-in SubLink must also be removed from its original position in the
  * query quals, since the quals of the returned JoinExpr replace it.
  * (Notionally, we replace the SubLink with a constant TRUE, then elide the
  * redundant constant from the qual.)
  *
  * On success, the caller is also responsible for recursively applying
  * pull_up_sublinks processing to the rarg and quals of the returned JoinExpr.
  * (On failure, there is no need to do anything, since pull_up_sublinks will
  * be applied when we recursively plan the sub-select.)
  *
  * Side effects of a successful conversion include adding the SubLink's
  * subselect to the query's rangetable, so that it can be referenced in
  * the JoinExpr's rarg.
  */
 JoinExpr *
 convert_ANY_sublink_to_join(PlannerInfo *root, SubLink *sublink,
                             Relids available_rels)
 {
     JoinExpr   *result;
     Query      *parse = root->parse;
     Query      *subselect = (Query *) sublink->subselect;
     Relids      upper_varnos;
     int         rtindex;
     RangeTblEntry *rte;
     RangeTblRef *rtr;
     List       *subquery_vars;
     Node       *quals;
     ParseState *pstate;
 
     Assert(sublink->subLinkType == ANY_SUBLINK);
 
     /*
      * The sub-select must not refer to any Vars of the parent query. (Vars of
      * higher levels should be okay, though.)
      */
     //ANY类型的子链接,子查询不能依赖父查询的任何变量,否则返回NULL(不能上拉)
     if (contain_vars_of_level((Node *) subselect, 1))
         return NULL;
 
     /*
      * The test expression must contain some Vars of the parent query, else
      * it's not gonna be a join.  (Note that it won't have Vars referring to
      * the subquery, rather Params.)
      */
     //子查询的testexpr变量中必须含有父查询的某些Vars,否则不能上拉(join),返回NULL
     upper_varnos = pull_varnos(sublink->testexpr);
     if (bms_is_empty(upper_varnos))
         return NULL;
 
     /*
      * However, it can't refer to anything outside available_rels.
      */
     //但是不能够依赖超出可用的范围之内,否则一样不能上拉
     if (!bms_is_subset(upper_varnos, available_rels))
         return NULL;
 
     /*
      * The combining operators and left-hand expressions mustn't be volatile.
      */
     //组合操作符和左侧的表达式不能是易变(volatile)的,比如随机数等
     if (contain_volatile_functions(sublink->testexpr))
         return NULL;
   
     //校验通过,上拉
     /* Create a dummy ParseState for addRangeTableEntryForSubquery */
     pstate = make_parsestate(NULL);
 
     /*
      * Okay, pull up the sub-select into upper range table.
      *
      * We rely here on the assumption that the outer query has no references
      * to the inner (necessarily true, other than the Vars that we build
      * below). Therefore this is a lot easier than what pull_up_subqueries has
      * to go through.
      */
     //子链接上拉后,子查询变成了上层的RTE,在这里构造
     rte = addRangeTableEntryForSubquery(pstate,
                                         subselect,
                                         makeAlias("ANY_subquery", NIL),
                                         false,
                                         false);
     //添加到上层的rtable中
     parse->rtable = lappend(parse->rtable, rte);
     //rtable中的索引
     rtindex = list_length(parse->rtable);
 
     /*
      * Form a RangeTblRef for the pulled-up sub-select.
      */
     //产生了RTE,自然要生成RTR(RangeTblRef)
     rtr = makeNode(RangeTblRef);
     rtr->rtindex = rtindex;
 
     /*
      * Build a list of Vars representing the subselect outputs.
      */
     //创建子查询的输出列(投影)
     subquery_vars = generate_subquery_vars(root,
                                            subselect->targetList,
                                            rtindex);
 
     /*
      * Build the new join's qual expression, replacing Params with these Vars.
      */
     //构造上层的条件表达式
     quals = convert_testexpr(root, sublink->testexpr, subquery_vars);
 
     /*
      * And finally, build the JoinExpr node.
      */
     //构造返回结果
     result = makeNode(JoinExpr);
     result->jointype = JOIN_SEMI;//变换为半连接
     result->isNatural = false;
     result->larg = NULL;        /* caller must fill this in */
     result->rarg = (Node *) rtr;
     result->usingClause = NIL;
     result->quals = quals;
     result->alias = NULL;
     result->rtindex = 0;        /* we don't need an RTE for it */
 
     return result;
 }

三、数据结构

Param

 
 /*
  * Param
  *
  *      paramkind specifies the kind of parameter. The possible values
  *      for this field are:
  *
  *      PARAM_EXTERN:  The parameter value is supplied from outside the plan.
  *              Such parameters are numbered from 1 to n.
  *
  *      PARAM_EXEC:  The parameter is an internal executor parameter, used
  *              for passing values into and out of sub-queries or from
  *              nestloop joins to their inner scans.
  *              For historical reasons, such parameters are numbered from 0.
  *              These numbers are independent of PARAM_EXTERN numbers.
  *
  *      PARAM_SUBLINK:  The parameter represents an output column of a SubLink
  *              node's sub-select.  The column number is contained in the
  *              `paramid' field.  (This type of Param is converted to
  *              PARAM_EXEC during planning.)
  *
  *      PARAM_MULTIEXPR:  Like PARAM_SUBLINK, the parameter represents an
  *              output column of a SubLink node's sub-select, but here, the
  *              SubLink is always a MULTIEXPR SubLink.  The high-order 16 bits
  *              of the `paramid' field contain the SubLink's subLinkId, and
  *              the low-order 16 bits contain the column number.  (This type
  *              of Param is also converted to PARAM_EXEC during planning.)
  */
 typedef enum ParamKind
 {
     PARAM_EXTERN,
     PARAM_EXEC,
     PARAM_SUBLINK,
     PARAM_MULTIEXPR
 } ParamKind;
 
 typedef struct Param
 {
     Expr        xpr;
     ParamKind   paramkind;      /* kind of parameter. See above */
     int         paramid;        /* numeric ID for parameter */
     Oid         paramtype;      /* pg_type OID of parameter's datatype */
     int32       paramtypmod;    /* typmod value, if known */
     Oid         paramcollid;    /* OID of collation, or InvalidOid if none */
     int         location;       /* token location, or -1 if unknown */
 } Param;

四、跟踪分析

测试脚本:

select * 
from t_dwxx a
where dwbh > any (select b.dwbh from t_grxx b);

gdb跟踪:

(gdb) b pull_up_sublinks
Breakpoint 1 at 0x77cbc6: file prepjointree.c, line 157.
(gdb) c
Continuing.

Breakpoint 1, pull_up_sublinks (root=0x249f318) at prepjointree.c:157
157                                                (Node *) root->parse->jointree,
(gdb) 
#输入参数root->parse是查询树
#查询树结构见第2小结中的查询树图
...
(gdb) p *root->parse
$2 = {type = T_Query, commandType = CMD_SELECT, querySource = QSRC_ORIGINAL, queryId = 0, canSetTag = true, 
  utilityStmt = 0x0, resultRelation = 0, hasAggs = false, hasWindowFuncs = false, hasTargetSRFs = false, 
  hasSubLinks = true, hasDistinctOn = false, hasRecursive = false, hasModifyingCTE = false, hasForUpdate = false, 
  hasRowSecurity = false, cteList = 0x0, rtable = 0x23b0798, jointree = 0x23d3290, targetList = 0x23b0bc8, 
  override = OVERRIDING_NOT_SET, onConflict = 0x0, returningList = 0x0, groupClause = 0x0, groupingSets = 0x0, 
  havingQual = 0x0, windowClause = 0x0, distinctClause = 0x0, sortClause = 0x0, limitOffset = 0x0, limitCount = 0x0, 
  rowMarks = 0x0, setOperations = 0x0, constraintDeps = 0x0, withCheckOptions = 0x0, stmt_location = 0, stmt_len = 70}
(gdb) 
#第1次进入pull_up_sublinks_jointree_recurse
(gdb) n
156     jtnode = pull_up_sublinks_jointree_recurse(root,
(gdb) step
pull_up_sublinks_jointree_recurse (root=0x249f318, jtnode=0x23d3290, relids=0x7ffc4fd1ad90) at prepjointree.c:180
180     if (jtnode == NULL)
(gdb) n
184     else if (IsA(jtnode, RangeTblRef))
(gdb) 
206             newchild = pull_up_sublinks_jointree_recurse(root,
(gdb) p *jtnode
$3 = {type = T_FromExpr}
(gdb) 
#第2次调用pull_up_sublinks_jointree_recurse,输入参数的jtnode为RangeTblRef
#第2次调用后返回信息
(gdb) n
209             newfromlist = lappend(newfromlist, newchild);
(gdb) p *(RangeTblRef *)newchild
$8 = {type = T_RangeTblRef, rtindex = 1}
...
#进入pull_up_sublinks_qual_recurse
(gdb) step
pull_up_sublinks_qual_recurse (root=0x249f318, node=0x23b00e8, jtlink1=0x7ffc4fd1ad28, available_rels1=0x249fa98, 
    jtlink2=0x0, available_rels2=0x0) at prepjointree.c:335
335     if (node == NULL)
#1.root=PlannerInfo
#2.node=f->quals,即SubLink(结构参见查询树图)
#3.jtlink1=FromExpr(指针数组)
(gdb) p **(FromExpr **)jtlink1
$29 = {type = T_FromExpr, fromlist = 0x246e0b8, quals = 0x0}
...
#进入convert_ANY_sublink_to_join
(gdb) 
346       if ((j = convert_ANY_sublink_to_join(root, sublink,
(gdb) 
#输入参数
#1.root见上
#2.sublink,子链接
#3.available_rels,可用的rels
...
#sublink中的子查询
1322    Query    *subselect = (Query *) sublink->subselect;
(gdb) 
1337    if (contain_vars_of_level((Node *) subselect, 1))
(gdb) p *subselect
$2 = {type = T_Query, commandType = CMD_SELECT, 
  querySource = QSRC_ORIGINAL, queryId = 0, canSetTag = true, 
  utilityStmt = 0x0, resultRelation = 0, hasAggs = false, 
  hasWindowFuncs = false, hasTargetSRFs = false, 
  hasSubLinks = false, hasDistinctOn = false, 
  hasRecursive = false, hasModifyingCTE = false, 
  hasForUpdate = false, hasRowSecurity = false, cteList = 0x0, 
  rtable = 0x1cb1030, jointree = 0x1cb1240, 
  targetList = 0x1cb1210, override = OVERRIDING_NOT_SET, 
  onConflict = 0x0, returningList = 0x0, groupClause = 0x0, 
  groupingSets = 0x0, havingQual = 0x0, windowClause = 0x0, 
  distinctClause = 0x0, sortClause = 0x0, limitOffset = 0x0, 
  limitCount = 0x0, rowMarks = 0x0, setOperations = 0x0, 
  constraintDeps = 0x0, withCheckOptions = 0x0, 
  stmt_location = 0, stmt_len = 0}
...
(gdb) p *upper_varnos.words
$4 = 2
(gdb) p available_rels
$5 = (Relids) 0x1c8ab68
(gdb) p *available_rels
$6 = {nwords = 1, words = 0x1c8ab6c}
(gdb) p *available_rels.words
$7 = 2
...
#子链接被上拉为上一层jointree的rarg
#larg由上层填充
1411    return result;
(gdb) p *result
$10 = {type = T_JoinExpr, jointype = JOIN_SEMI, 
  isNatural = false, larg = 0x0, rarg = 0x1c96e88, 
  usingClause = 0x0, quals = 0x1c96ef0, alias = 0x0, 
  rtindex = 0}
(gdb) n
1412  }
(gdb) n
#回到pull_up_sublinks_qual_recurse
pull_up_sublinks_qual_recurse (root=0x1c8a3e8, node=0x1bc1038, 
    jtlink1=0x7ffc99e060e8, available_rels1=0x1c8ab68, 
    jtlink2=0x0, available_rels2=0x0) at prepjointree.c:350
350         j->larg = *jtlink1;
(gdb) n
351         *jtlink1 = (Node *) j;
#larg为RTF(rtindex=1)
(gdb) p *jtlink1
$13 = (Node *) 0x1c96ca8
(gdb) p **jtlink1
$14 = {type = T_FromExpr}
(gdb) p **(FromExpr **)jtlink1
$15 = {type = T_FromExpr, fromlist = 0x1c96c78, quals = 0x0}
(gdb) p **(FromExpr **)jtlink1->fromlist
There is no member named fromlist.
(gdb) p *(*(FromExpr **)jtlink1)->fromlist
$16 = {type = T_List, length = 1, head = 0x1c96c58, 
  tail = 0x1c96c58}
(gdb) p *(Node *)(*(FromExpr **)jtlink1)->fromlist->head->data.ptr_value
$17 = {type = T_RangeTblRef}
(gdb) p *(RangeTblRef *)(*(FromExpr **)jtlink1)->fromlist->head->data.ptr_value
$18 = {type = T_RangeTblRef, rtindex = 1}
#递归上拉右树
(gdb) step
pull_up_sublinks_jointree_recurse (root=0x1c8a3e8, 
    jtnode=0x1c96e88, relids=0x7ffc99e06048)
    at prepjointree.c:180
180   if (jtnode == NULL)
(gdb) p *jtnode
$19 = {type = T_RangeTblRef}
#RTR,退出
(gdb) finish
Run till exit from #0  pull_up_sublinks_jointree_recurse (
    root=0x1c8a3e8, jtnode=0x1c96e88, relids=0x7ffc99e06048)
    at prepjointree.c:180
0x000000000077d00a in pull_up_sublinks_qual_recurse (
    root=0x1c8a3e8, node=0x1bc1038, jtlink1=0x7ffc99e060e8, 
    available_rels1=0x1c8ab68, jtlink2=0x0, available_rels2=0x0)
    at prepjointree.c:353
353         j->rarg = pull_up_sublinks_jointree_recurse(root,
Value returned is $20 = (Node *) 0x1c96e88
(gdb) n
362         j->quals = pull_up_sublinks_qual_recurse(root,
(gdb) step
#递归上拉条件表达式,节点类型为OpExpr,无需处理
Breakpoint 1, pull_up_sublinks_qual_recurse (root=0x1c8a3e8, 
    node=0x1c96ef0, jtlink1=0x1c97100, 
    available_rels1=0x1c8ab68, jtlink2=0x1c97108, 
    available_rels2=0x1c97140) at prepjointree.c:335
335   if (node == NULL)
(gdb) n
337   if (IsA(node, SubLink))
(gdb) p *node
$21 = {type = T_OpExpr}
...
369         return NULL;
(gdb) 
552 }
(gdb) 
#回到pull_up_sublinks_jointree_recurse
pull_up_sublinks_jointree_recurse (root=0x1c8a3e8, 
    jtnode=0x1cb1540, relids=0x7ffc99e06150)
    at prepjointree.c:230
230     *relids = frelids;
(gdb) p *newf
#newf的条件表达式为NULL(TRUE)
$22 = {type = T_FromExpr, fromlist = 0x1c96c78, quals = 0x0}
(gdb) p *jtlink
$23 = {type = T_JoinExpr}
(gdb) n
231     jtnode = jtlink;
(gdb) n
312   return jtnode;
(gdb) 
313 }
(gdb) 
pull_up_sublinks (root=0x1c8a3e8) at prepjointree.c:164
164   if (IsA(jtnode, FromExpr))
(gdb) 
167     root->parse->jointree = makeFromExpr(list_make1(jtnode), NULL);
(gdb) 
168 }
(gdb) 
subquery_planner (glob=0x1bc1d50, parse=0x1bc1328, 
    parent_root=0x0, hasRecursion=false, tuple_fraction=0)
    at planner.c:656
warning: Source file is more recent than executable.
656   inline_set_returning_functions(root);
(gdb) finish
Run till exit from #0  subquery_planner (glob=0x1bc1d50, 
    parse=0x1bc1328, parent_root=0x0, hasRecursion=false, 
    tuple_fraction=0) at planner.c:656
0x0000000000769a49 in standard_planner (parse=0x1bc1328, 
    cursorOptions=256, boundParams=0x0) at planner.c:405
405   root = subquery_planner(glob, parse, NULL,
Value returned is $24 = (PlannerInfo *) 0x1c8a3e8
(gdb) 
#DONE!

“PostgreSQL查询优化中如何实现上拉子链接”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!

推荐阅读:
  1. AnglarJs中如何实现上拉加载
  2. postgresql的链接方式有哪些

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

postgresql

上一篇:PostgreSQL查询优化中怎么上拉子链接

下一篇:Django中的unittest应用是什么

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》