iis服务器助手广告广告
返回顶部
首页 > 资讯 > 数据库 >PostgreSQL查询优化对表达式预处理中连接Var溯源的过程是什么
  • 470
分享到

PostgreSQL查询优化对表达式预处理中连接Var溯源的过程是什么

2024-04-02 19:04:59 470人浏览 八月长安
摘要

本篇内容介绍了“postgresql查询优化对表达式预处理中连接Var溯源的过程是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大

本篇内容介绍了“postgresql查询优化对表达式预处理中连接Var溯源的过程是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

处理逻辑在主函数subquery_planner中通过调用flatten_join_alias_vars函数实现,该函数位于src/backend/optimizer/util/var.c文件中。

一、基本概念

连接Var溯源,意思是把连接产生的中间结果(中间结果也是Relation关系的一种)的投影替换为实际存在的关系的列(在PG中通过Var表示)。
如下面的sql语句:

select a.*,b.grbh,b.je 
from t_dwxx a,
     lateral (select t1.dwbh,t1.grbh,t2.je 
              from t_grxx t1 inner join t_jfxx t2 
                   on t1.dwbh = a.dwbh 
                      and t1.grbh = t2.grbh) b;

b与a连接运算,查询树Query中的投影b.grbh和b.je这两列如需依赖关系b(子查询产生的中间结果),则需要把中间关系的投影列替换为实际的Relation的投影列,即t_grxx和t_jfxx的数据列.

PG源码中的注释:

     
     if (root->hasJoinRTEs &&
         !(kind == EXPRKIND_RTFUNC ||
           kind == EXPRKIND_VALUES ||
           kind == EXPRKIND_TABLESAMPLE ||
           kind == EXPRKIND_TABLEFUNC))
        expr = flatten_join_alias_vars(root, expr);

二、源码解读

flatten_join_alias_vars


 node *
 flatten_join_alias_vars(PlannerInfo *root, Node *node)
 {
     flatten_join_alias_vars_context context;
 
     context.root = root;
     context.sublevels_up = 0;
     
     context.possible_sublink = root->parse->hasSubLinks;
     
     context.inserted_sublink = root->parse->hasSubLinks;
     //调用flatten_join_alias_vars_mutator处理Vars
     return flatten_join_alias_vars_mutator(node, &context);
 }
 
 static Node *
 flatten_join_alias_vars_mutator(Node *node,
                                 flatten_join_alias_vars_context *context)
 {
     if (node == NULL)
         return NULL;
     if (IsA(node, Var))//Var类型
     {
         Var        *var = (Var *) node;
         RangeTblEntry *rte;
         Node       *newvar;
 
         
         if (var->varlevelsup != context->sublevels_up)
             return node;        
         rte = rt_fetch(var->varno, context->root->parse->rtable);
         if (rte->rtekind != RTE_JOIN)
             return node;
         //在rte->rtekind == RTE_JOIN时才需要处理
         if (var->varattno == InvalidAttrNumber)
         {
             
             RowExpr    *rowexpr;
             List       *fields = NIL;
             List       *colnames = NIL;
             AttrNumber  attnum;
             ListCell   *lv;
             ListCell   *ln;
 
             attnum = 0;
             Assert(list_length(rte->joinaliasvars) == list_length(rte->eref->colnames));
             forboth(lv, rte->joinaliasvars, ln, rte->eref->colnames)
             {
                 newvar = (Node *) lfirst(lv);
                 attnum++;
                 
                 if (newvar == NULL)
                     continue;
                 newvar = copyObject(newvar);
 
                 
                 if (context->sublevels_up != 0)
                     IncrementVarSublevelsUp(newvar, context->sublevels_up, 0);
                 
                 if (IsA(newvar, Var))
                     ((Var *) newvar)->location = var->location;
                 
                 
                 newvar = flatten_join_alias_vars_mutator(newvar, context);
                 fields = lappend(fields, newvar);
                 
                 colnames = lappend(colnames, copyObject((Node *) lfirst(ln)));
             }
             rowexpr = makeNode(RowExpr);
             rowexpr->args = fields;
             rowexpr->row_typeid = var->vartype;
             rowexpr->row_fORMat = COERCE_IMPLICIT_CAST;
             rowexpr->colnames = colnames;
             rowexpr->location = var->location;
 
             return (Node *) rowexpr;
         }
 
         
         //扩展join alias Var
         Assert(var->varattno > 0);
         newvar = (Node *) list_nth(rte->joinaliasvars, var->varattno - 1);
         Assert(newvar != NULL);
         newvar = copyObject(newvar);
 
         
         if (context->sublevels_up != 0)
             IncrementVarSublevelsUp(newvar, context->sublevels_up, 0);
 
         
         if (IsA(newvar, Var))
             ((Var *) newvar)->location = var->location;
 
         
         newvar = flatten_join_alias_vars_mutator(newvar, context);
 
         
         if (context->possible_sublink && !context->inserted_sublink)
             context->inserted_sublink = checkExprHasSubLink(newvar);
 
         return newvar;
     }
     if (IsA(node, PlaceHolderVar))//占位符
     {
         
         PlaceHolderVar *phv;
 
         phv = (PlaceHolderVar *) expression_tree_mutator(node,
                                                          flatten_join_alias_vars_mutator,
                                                          (void *) context);
         
         if (phv->phlevelsup == context->sublevels_up)
         {
             phv->phrels = alias_relid_set(context->root,
                                           phv->phrels);
         }
         return (Node *) phv;
     }
 
     if (IsA(node, Query))//查询树
     {
         
         Query      *newnode;
         bool        save_inserted_sublink;
 
         context->sublevels_up++;
         save_inserted_sublink = context->inserted_sublink;
         context->inserted_sublink = ((Query *) node)->hasSubLinks;
         newnode = query_tree_mutator((Query *) node,
                                      flatten_join_alias_vars_mutator,
                                      (void *) context,
                                      QtW_IGNORE_JOINALIASES);
         newnode->hasSubLinks |= context->inserted_sublink;
         context->inserted_sublink = save_inserted_sublink;
         context->sublevels_up--;
         return (Node *) newnode;
     }
     
     Assert(!IsA(node, SubPlan));
     
     Assert(!IsA(node, SpecialJoinInfo));
     Assert(!IsA(node, PlaceHolderInfo));
     Assert(!IsA(node, MinMaxAggInfo));
     //其他表达式
     return expression_tree_mutator(node, flatten_join_alias_vars_mutator,
                                    (void *) context);
 }

query_tree_mutator

 
 Query *
 query_tree_mutator(Query *query,
                    Node *(*mutator) (),
                    void *context,
                    int flags)//遍历查询树
 {
     Assert(query != NULL && IsA(query, Query));
 
     if (!(flags & QTW_DONT_COPY_QUERY))
     {
         Query      *newquery;
 
         FLATCOPY(newquery, query, Query);
         query = newquery;
     }
 
     MUTATE(query->targetList, query->targetList, List *);//投影列
     MUTATE(query->withCheckOptions, query->withCheckOptions, List *);
     MUTATE(query->onConflict, query->onConflict, OnConflictExpr *);
     MUTATE(query->returningList, query->returningList, List *);
     MUTATE(query->jointree, query->jointree, FromExpr *);
     MUTATE(query->setOperations, query->setOperations, Node *);
     MUTATE(query->havingQual, query->havingQual, Node *);
     MUTATE(query->limitOffset, query->limitOffset, Node *);
     MUTATE(query->limitCount, query->limitCount, Node *);
     if (!(flags & QTW_IGNORE_CTE_SUBQUERIES))
         MUTATE(query->cteList, query->cteList, List *);
     else                        
         query->cteList = copyObject(query->cteList);
     query->rtable = range_table_mutator(query->rtable,
                                         mutator, context, flags);//RTE
     return query;
 }

range_table_mutator

 
 List *
 range_table_mutator(List *rtable,
                     Node *(*mutator) (),
                     void *context,
                     int flags)
 {
     List       *newrt = NIL;
     ListCell   *rt;
 
     foreach(rt, rtable)//遍历RTE
     {
         RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
         RangeTblEntry *newrte;
 
         FLATCOPY(newrte, rte, RangeTblEntry);
         switch (rte->rtekind)
         {
             case RTE_RELATION:
                 MUTATE(newrte->tablesample, rte->tablesample,
                        TableSampleClause *);
                 
                 break;
             case RTE_CTE:
             case RTE_NAMEDTUPLESTORE:
                 
                 break;
             case RTE_SUBQUERY:
                 if (!(flags & QTW_IGNORE_RT_SUBQUERIES))
                 {
                     CHECKFLATCOPY(newrte->subquery, rte->subquery, Query);
                     MUTATE(newrte->subquery, newrte->subquery, Query *);//遍历处理子查询
                 }
                 else
                 {
                     
                     newrte->subquery = copyObject(rte->subquery);
                 }
                 break;
             case RTE_JOIN://连接,遍历处理joinaliasvars
                 if (!(flags & QTW_IGNORE_JOINALIASES))
                     MUTATE(newrte->joinaliasvars, rte->joinaliasvars, List *);
                 else
                 {
                     
                     newrte->joinaliasvars = copyObject(rte->joinaliasvars);
                 }
                 break;
             case RTE_FUNCTION:
                 MUTATE(newrte->functions, rte->functions, List *);
                 break;
             case RTE_TABLEFUNC:
                 MUTATE(newrte->tablefunc, rte->tablefunc, TableFunc *);
                 break;
             case RTE_VALUES:
                 MUTATE(newrte->values_lists, rte->values_lists, List *);
                 break;
         }
         MUTATE(newrte->securityQuals, rte->securityQuals, List *);
         newrt = lappend(newrt, newrte);
     }
     return newrt;
 }

三、跟踪分析

在PG11中,没有进入"Expand join alias reference"的实现逻辑,猜测在上拉子查询的时候已作优化.

“PostgreSQL查询优化对表达式预处理中连接Var溯源的过程是什么”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

您可能感兴趣的文档:

--结束END--

本文标题: PostgreSQL查询优化对表达式预处理中连接Var溯源的过程是什么

本文链接: https://www.lsjlt.com/news/65008.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • PostgreSQL查询优化对表达式预处理中连接Var溯源的过程是什么
    本篇内容介绍了“PostgreSQL查询优化对表达式预处理中连接Var溯源的过程是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大...
    99+
    2022-10-19
  • PostgreSQL查询优化中对消除外连接的处理过程是什么
    本篇内容介绍了“PostgreSQL查询优化中对消除外连接的处理过程是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,...
    99+
    2022-10-19
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作