原 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操作。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏拭心的安卓进阶之路

Java 集合深入理解(13):Stack 栈

今天心情不错,再来一篇 Stack ! 数据结构中的 栈 数据结构中,栈是一种线性数据结构,遵从 LIFO(后进先出)的操作顺序,所有操作都是在顶部进行 ...

21110
来自专栏跟着阿笨一起玩NET

VB.NET自我总结语法

1061
来自专栏分布式系统和大数据处理

.Net中的反射(动态创建类型实例) - Part.4

在前面节中,我们先了解了反射,然后利用反射查看了类型信息,并学习了如何创建自定义特性,并利用反射来遍历它。可以说,前面三节,我们学习的都是反射是什么,在接下来的...

1343
来自专栏Fish

UVA-12096 The SetStack Computer

白书的例题,而且提示十分重要,所以就做了一下。 先说题意 维护 N(1≤N≤2000) 个操作, 可能的五种操作如下: PUSH: 在栈顶加入一个空集合 A=...

2147
来自专栏一个会写诗的程序员的博客

MySql 计算两个日期的时间差函数

返回日期或日期时间表达式datetime_expr1 和datetime_expr2the 之间的整数差。其结果的 单位由interval 参数给出。inte...

651
来自专栏Code_iOS

数据结构:链表

工程代码 Github: Data_Structures_C_Implemention -- Link List

1451
来自专栏lonelydawn的前端猿区

打造专属插件之Easy Slider Bar

引用 <link rel="stylesheet" type="text/css" href="./index.css"> <div id="slider"><...

3275
来自专栏企鹅号快讯

编写高效简洁代码的那些招式1

高效的代码,每期都会给大家介绍一下编码的技巧,让我们代码更整洁更高效。我们会从python 语言切入,讲一讲如何写的代码更pythonic 。Pythonic ...

1836
来自专栏黒之染开发日记

gps相关

1、JavaScript版:通过两个gps坐标计算两点之间实际距离(因为考虑到地球的半径,准确度还行) 其实是直接把这篇文章的java版改成js版而已

761
来自专栏函数式编程语言及工具

Scalaz(58)- scalaz-stream: fs2-并行运算示范,fs2 parallel processing

    从表面上来看,Stream代表一连串无穷数据元素。一连串的意思是元素有固定的排列顺序,所以对元素的运算也必须按照顺序来:完成了前面的运算再跟着进行下一个...

2148

扫码关注云+社区

领取腾讯云代金券