瀚高数据库
目录
文档用途
详细信息
文档用途
了解exist类型的子连接提升过程
详细信息
SQL:
SELECT sno FROM STUDENT WHERE EXISTS (SELECT sno FROM score WHERE sno > STUDENT.sno);
一、执行计划:
test=# explain SELECT sno FROM STUDENT WHERE EXISTS (SELECT sno FROM score WHERE sno > STUDENT.sno);
QUERY PLAN
---------------------------------------------------------------------
Nested Loop Semi Join (cost=0.00..22497.30 rows=367 width=4)
Join Filter: (score.sno > student.sno)
-> Seq Scan on student (cost=0.00..21.00 rows=1100 width=4)
-> Materialize (cost=0.00..40.60 rows=2040 width=4)
-> Seq Scan on score (cost=0.00..30.40 rows=2040 width=4)
(5 rows)
查询树:
优化后的查询树:
优化前和优化后查询树对比结合该sql的执行计划,EXIST类型的子连接提升主要操作包括:
1.SUBLINK->subselect->rtable提升到上层,和上层表构成Semi Join关系。
2.优化后的JoinExpr中的quals是Sublink->subselect->FromExpr->quals提升上来的。
3.将子连接的范围表和约束条件提升之后,需要调整subselect查询树中的Var变量中的varno和varlevelsup。
根据优化后的查询树对应的SQL是:
SELECT sno FROM student SEMI JOIN score WHERE score .sno > student .sno;
二、提升流程
- quals单独保存到whereClause作为约束条件
whereClause = subselect->jointree->quals;
subselect->jointree->quals = NULL;
- 对subselect和whereClause分别处理,目前它们中的 Var 变量的 varno 是根据 SubLink->subselect->rtable 确定的,如果这些 Var 被提升到上层,它们的 varno 就要做调整,由于要将子连接中的范围表追加到上层父查询的范围表的链表中 (rtable链表),因此子连接中的范围表的 rtindex 需要增加上层父查询的范围表链表的长度,同时对 SubLink-> subselect 中的 RangeTableRef rtindex 要按照新的 rtindex 做调整。这个在上述查询树中可以直观体现。
rtoffset = list_length(parse->rtable);
OffsetVarNodes((Node *) subselect, rtoffset, 0);
OffsetVarNodes(whereClause, rtoffset, 0);
if (IsA(node, Var))
{
Var *var = (Var *) node;
if (var->varlevelsup == context->sublevels_up)
{
var->varno += context->offset;
var->varnullingrels = offset_relid_set(var->varnullingrels,
context->offset);
if (var->varnosyn > 0)
var->varnosyn += context->offset;
}
return false;
}
- 对 Sublink->subselect和whereClause 分别处理,如果引用了上层表的列属性,那么这个 Var的varlevelup 的值表示它是上一层的某个表的列属性,如果子连接被提升, 这个Var的varlevelsup 应该做出调整,调成为原来的值-1
IncrementVarSublevelsUp((Node *) subselect, -1, 1);
IncrementVarSublevelsUp(whereClause, -1, 1);
if (IsA(node, Var))
{
Var *var = (Var *) node;
if (var->varlevelsup >= context->min_sublevels_up)
var->varlevelsup += context->delta_sublevels_up;
return false; /* done here */
}
- 将子连接的rtable附加到父查询的rtable
CombineRangeTables(&parse->rtable, &parse->rteperminfos,
subselect->rtable, subselect->rteperminfos);
- 创建新的JoinTree,用subselect中的JoinTree的fromlist作为右参数,whereClause作为新的Join关系的quals
result = makeNode(JoinExpr);
result->jointype = under_not ? JOIN_ANTI : JOIN_SEMI;
result->isNatural = false;
result->larg = NULL; /* caller must fill this in */
/* flatten out the FromExpr node if it's useless */
if (list_length(subselect->jointree->fromlist) == 1)
result->rarg = (Node *) linitial(subselect->jointree->fromlist);
else
result->rarg = (Node *) subselect->jointree;
result->quals = whereClause;
PG处理ANY和EXIST类型的子连接,两者最主要的不同是ANY类型的子连接提升为子查询,而EXIST类型的子连接提升为表与表直接相连的方式。
标签:subselect,sno,查询,var,rtable,EXIST,whereClause,Var,连接 From: https://blog.csdn.net/pg_hgdb/article/details/136807420