共计 23169 个字符,预计需要花费 58 分钟才能阅读完成。
本篇内容介绍了“PostgreSQL 查询优化中如何实现上拉子链接”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让丸趣 TV 小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
查询树
/*
* 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 查询优化中如何实现上拉子链接”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注丸趣 TV 网站,丸趣 TV 小编将为大家输出更多高质量的实用文章!
正文完