前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >原 pg查询树的简单解读

原 pg查询树的简单解读

作者头像
王果壳
发布2018-05-17 11:12:11
1.1K0
发布2018-05-17 11:12:11
举报
文章被收录于专栏:王硕王硕

准备环境: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操作。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档