查询优化-EXIST类型子连接提升

本文详细解析了瀚高数据库中Exist类型的子连接提升过程,包括执行计划分析、优化步骤以及流程,重点介绍了如何通过子链接、范围表调整和JoinExpr来优化查询效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

瀚高数据库
目录
文档用途
详细信息

文档用途
了解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)

查询树:

正在上传...sample21.node.jpg

优化后的查询树:

sample20.node.jpg

优化前和优化后查询树对比结合该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;

二、提升流程

  1. quals单独保存到whereClause作为约束条件
whereClause = subselect->jointree->quals;

subselect->jointree->quals = NULL;
  1. 对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;

}
  1. 对 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 */

}

image.png

image.png

  1. 将子连接的rtable附加到父查询的rtable
CombineRangeTables(&parse->rtable, &parse->rteperminfos,

			subselect->rtable, subselect->rteperminfos);
  1. 创建新的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类型的子连接提升为表与表直接相连的方式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值