pg查询树的简单解读

准备环境:PostgreSQL 9.2
前提准备: debug_print_parse = on
                 debug_print_rewritten = on
                 debug_print_plan = on
                 debug_pretty_print = on
启动条件:-l logfile(为了更好的查看log)
表:create  table  aa(a int,b int);
数据:insert into aa values (0,1),(1,0),(1,1);
执行查询语句: select * from aa where ((4-3)/a>1 and a>0);
LOG:  parse tree:
DETAIL:     {QUERY 
   :commandType 1 
   :querySource 0 
   :canSetTag true 
   :utilityStmt <> 
   :resultRelation 0 
   :hasAggs false 
   :hasWindowFuncs false 
   :hasSubLinks false 
   :hasDistinctOn false 
   :hasRecursive false 
   :hasModifyingCTE false 
   :hasForUpdate false 
   :cteList <> 
   :rtable (
      {RTE 
      :alias <> 
      :eref 
         {ALIAS 
         :aliasname aa 
         :colnames ("a" "b")
         }
      :rtekind 0 
      :relid 16384 
      :relkind r 
      :inh true 
      :inFromCl true 
      :requiredPerms 2 
      :checkAsUser 0 
      :selectedCols (b 9 10)
      :modifiedCols (b)
      }
   )
   :jointree 
      {FROMEXPR 
      :fromlist (
         {RANGETBLREF 
         :rtindex 1
         }
      )
      :quals 
         {BOOLEXPR 
         :boolop and 
         :args ( //这里重点说一下参数,主要看的是参数。表达式是((4-3)/a>1 and a>0),一共有6个参数
            {OPEXPR  // 操作符
            :opno 521 // 操作符oid ">"
            :opfuncid 147 // 调用的函数oid int4gt
            :opresulttype 16  // 返回的数据类型oid bool
            :opretset false 
            :opcollid 0 
            :inputcollid 0 
            :args (
               {OPEXPR  // 操作符
               :opno 528  // 操作符oid "/"
               :opfuncid 154  // 调用的函数oid int4div
               :opresulttype 23 // 返回的数据类型oid int4
               :opretset false 
               :opcollid 0 
               :inputcollid 0 
               :args (
                  {OPEXPR  // 操作符
                  :opno 555  // 操作符oid "-"
                  :opfuncid 181 // 调用的函数oid int4mi
                  :opresulttype 23 // 返回的数据类型oid int4
                  :opretset false 
                  :opcollid 0 
                  :inputcollid 0 
                  :args (
                     {CONST //常数
                     :consttype 23 //常量数据类型oid int4
                     :consttypmod -1 //常量的typmod(现在不是很明白typmod,只知道是数据的一个属性,常为-1)
                     :constcollid 0 
                     :constlen 4 //常量数据的长度
                     :constbyval true 
                     :constisnull false 
                     :location 25 
                     :constvalue 4 [ 4 0 0 0 0 0 0 0 ] //第一个参数:4
                     }
                     {CONST //常数
                     :consttype 23 //常量数据类型oid int4
                     :consttypmod -1 //常量的typmod(现在不是很明白typmod,只知道是数据的一个属性,常为-1)
                     :constcollid 0 
                     :constlen 4 //常量数据的长度
                     :constbyval true 
                     :constisnull false 
                     :location 27 
                     :constvalue 4 [ 3 0 0 0 0 0 0 0 ] //第二个参数:3
                     }
                  )
                  :location 26
                  }
                  {VAR  //变量,就是涉及列的数据,第三个参数:a
                  :varno 1 
                  :varattno 1 
                  :vartype 23 //变量的数据类型oid int4
                  :vartypmod -1 //变量的typmod
                  :varcollid 0 
                  :varlevelsup 0 
                  :varnoold 1 
                  :varoattno 1 
                  :location 30
                  }
               )
               :location 29
               }
               {CONST //常数
               :consttype 23 //常量数据类型oid int4
               :consttypmod -1  //常量的typmod
               :constcollid 0 
               :constlen 4  //常量数据的长度
               :constbyval true 
               :constisnull false 
               :location 32 
               :constvalue 4 [ 1 0 0 0 0 0 0 0 ] //第四个参数:1
               }
            )
            :location 31
            }
            {OPEXPR  // 操作符
            :opno 521  // 操作符oid ">"
            :opfuncid 147  // 调用的函数oid int4gt
            :opresulttype 16  // 返回的数据类型oid bool
            :opretset false 
            :opcollid 0 
            :inputcollid 0 
            :args (
               {VAR  //变量,就是涉及列的数据,第五个参数:a
               :varno 1 
               :varattno 1 
               :vartype 23  //变量的数据类型oid int4
               :vartypmod -1  //变量的typmod
               :varcollid 0 
               :varlevelsup 0 
               :varnoold 1 
               :varoattno 1 
               :location 38
               }
               {CONST  //常数
               :consttype 23  //常量数据类型oid int4
               :consttypmod -1  //常量的typmod
               :constcollid 0 
               :constlen 4  //常量数据的长度
               :constbyval true 
               :constisnull false 
               :location 40 
               :constvalue 4 [ 0 0 0 0 0 0 0 0 ] //第六个参数:0
               }
            )
            :location 39
            }
         )
         :location 34
         }
      }
   :targetList ( //因为是*,所以需要输出的列是a、b
      {TARGETENTRY 
      :expr 
         {VAR 
         :varno 1 
         :varattno 1 
         :vartype 23 
         :vartypmod -1 
         :varcollid 0 
         :varlevelsup 0 
         :varnoold 1 
         :varoattno 1 
         :location 7
         }
      :resno 1 
      :resname a 
      :ressortgroupref 0 
      :resorigtbl 16384 
      :resorigcol 1 
      :resjunk false
      }
      {TARGETENTRY 
      :expr 
         {VAR 
         :varno 1 
         :varattno 2 
         :vartype 23 
         :vartypmod -1 
         :varcollid 0 
         :varlevelsup 0 
         :varnoold 1 
         :varoattno 2 
         :location 7
         }
      :resno 2 
      :resname b 
      :ressortgroupref 0 
      :resorigtbl 16384 
      :resorigcol 2 
      :resjunk false
      }
   )
   :returningList <> 
   :groupClause <> 
   :havingQual <> 
   :windowClause <> 
   :distinctClause <> 
   :sortClause <> 
   :limitOffset <> 
   :limitCount <> 
   :rowMarks <> 
   :setOperations <> 
   :constraintDeps <>
   }
STATEMENT:  select * from aa where ((4-3)/a>1 and a>0);
下面是执行计划的结构体:
/* ----------------
 * PlannedStmt node
 *
 * The output of the planner is a Plan tree headed by a PlannedStmt node.
 * PlannedStmt holds the "one time" information needed by the executor.
 * ----------------
 */
typedef struct PlannedStmt
{
NodeTag type;

CmdType commandType; /* select|insert|update|delete */

uint32 queryId; /* query identifier (copied from Query) */

bool hasReturning; /* is it insert|update|delete RETURNING? */

bool hasModifyingCTE; /* has insert|update|delete in WITH? */

bool canSetTag; /* do I set the command result tag? */

bool transientPlan; /* redo plan when TransactionXmin changes? */

struct Plan *planTree; /* tree of Plan nodes */

List    *rtable; /* list of RangeTblEntry nodes */

/* rtable indexes of target relations for INSERT/UPDATE/DELETE */
List    *resultRelations; /* integer list of RT indexes, or NIL */

Node    *utilityStmt; /* non-null if this is DECLARE CURSOR */

List    *subplans; /* Plan trees for SubPlan expressions */

Bitmapset  *rewindPlanIDs; /* indices of subplans that require REWIND */

List    *rowMarks; /* a list of PlanRowMark's */

List    *relationOids; /* OIDs of relations the plan depends on */

List    *invalItems; /* other dependencies, as PlanInvalItems */

int nParamExec; /* number of PARAM_EXEC Params used */
} PlannedStmt;

rewrite未对节点的顺序进行修改,这里就不做讨论了,下面是执行计划,这对节点的顺序发生了修改。

LOG:  plan:
DETAIL:     {PLANNEDSTMT 
   :commandType 1 
   :queryId 0 
   :hasReturning false 
   :hasModifyingCTE false 
   :canSetTag true 
   :transientPlan false 
   :planTree 
      {SEQSCAN //执行计划看到的估算值
      :startup_cost 0.00 
      :total_cost 47.45 
      :plan_rows 238 
      :plan_width 8 
      :targetlist (
         {TARGETENTRY 
         :expr 
            {VAR 
            :varno 1 
            :varattno 1 
            :vartype 23 
            :vartypmod -1 
            :varcollid 0 
            :varlevelsup 0 
            :varnoold 1 
            :varoattno 1 
            :location 7
            }
         :resno 1 
         :resname a 
         :ressortgroupref 0 
         :resorigtbl 16384 
         :resorigcol 1 
         :resjunk false
         }
         {TARGETENTRY 
         :expr 
            {VAR 
            :varno 1 
            :varattno 2 
            :vartype 23 
            :vartypmod -1 
            :varcollid 0 
            :varlevelsup 0 
            :varnoold 1 
            :varoattno 2 
            :location 7
            }
         :resno 2 
         :resname b 
         :ressortgroupref 0 
         :resorigtbl 16384 
         :resorigcol 2 
         :resjunk false
         }
      )
      :qual (
         {OPEXPR 
         :opno 521 
         :opfuncid 147 
         :opresulttype 16 
         :opretset false 
         :opcollid 0 
         :inputcollid 0 
         :args (
            {VAR 
            :varno 1 
            :varattno 1 
            :vartype 23 
            :vartypmod -1 
            :varcollid 0 
            :varlevelsup 0 
            :varnoold 1 
            :varoattno 1 
            :location 38
            }
            {CONST 
            :consttype 23 
            :consttypmod -1 
            :constcollid 0 
            :constlen 4 
            :constbyval true 
            :constisnull false 
            :location 40 
            :constvalue 4 [ 0 0 0 0 0 0 0 0 ]
            }
         )
         :location 39
         }
         {OPEXPR 
         :opno 521 
         :opfuncid 147 
         :opresulttype 16 
         :opretset false 
         :opcollid 0 
         :inputcollid 0 
         :args (
            {OPEXPR 
            :opno 528 
            :opfuncid 154 
            :opresulttype 23 
            :opretset false 
            :opcollid 0 
            :inputcollid 0 
            :args (
               {CONST 
               :consttype 23 
               :consttypmod -1 
               :constcollid 0 
               :constlen 4 
               :constbyval true 
               :constisnull false 
               :location -1 
               :constvalue 4 [ 1 0 0 0 0 0 0 0 ]
               }
               {VAR 
               :varno 1 
               :varattno 1 
               :vartype 23 
               :vartypmod -1 
               :varcollid 0 
               :varlevelsup 0 
               :varnoold 1 
               :varoattno 1 
               :location 30
               }
            )
            :location 29
            }
            {CONST 
            :consttype 23 
            :consttypmod -1 
            :constcollid 0 
            :constlen 4 
            :constbyval true 
            :constisnull false 
            :location 32 
            :constvalue 4 [ 1 0 0 0 0 0 0 0 ]
            }
         )
         :location 31
         }
      )
      :lefttree <> 
      :righttree <> 
      :initPlan <> 
      :extParam (b)
      :allParam (b)
      :scanrelid 1
      }
   :rtable (
      {RTE 
      :alias <> 
      :eref 
         {ALIAS 
         :aliasname aa 
         :colnames ("a" "b")
         }
      :rtekind 0 
      :relid 16384 
      :relkind r 
      :inh false 
      :inFromCl true 
      :requiredPerms 2 
      :checkAsUser 0 
      :selectedCols (b 9 10)
      :modifiedCols (b)
      }
   )
   :resultRelations <> 
   :utilityStmt <> 
   :subplans <> 
   :rewindPlanIDs (b)
   :rowMarks <> 
   :relationOids (o 16384)
   :invalItems <> 
   :nParamExec 0
   }
STATEMENT:  select * from aa where ((4-3)/a>1 and a>0);

经过查看,对一个查询做的操作如下(在此以上述的sql语句为例分析,只是针对where后的语句),这是解析时生成的树的结构(重写为对其进行更改):
(4 - 3) / a > 1 and a > 0

location 25 27

location 26 30

location 29 32 38 40

location 31 39

location 34

下面是执行的顺序:
a > 0 and (4 - 3) / a > 1

location 25 27

location 26 30

location 38 40 29 32

location 39 31

location 34

首先对这颗树进行介绍(以执行计划的顺序介绍,其中首先是进行了操作符优先级的解析,gram里解析的):
首先,这里的都是二叉树结构的,以深度优先进行遍历的,其中根节点是and(location:34),两个子节点分别是(a>0) 和 (4-3)/a>1 。
其中左子又以">"为根结点,a和0作为子节点,同样的右子是以">"为根结点,(4-3)/a和1为子节点,而(4-3)又是以"-"为根结点,4和3为
子节点。
当执行时,首先进行的是39节点的操作(a>0),而后进行的是26节点的操作(4-3),再进行29节点的操作(26,30节点的"/"操作),再进行31节点的操作,
然后在对39,40两个节点进行and操作。

转载于:https://my.oschina.net/Suregogo/blog/135663

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值