前提准备:
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);
执行查询语句:
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 ">"
:opresulttype 16
// 返回的数据类型oid bool
:opretset false
:opcollid 0
:inputcollid 0
:args (
{OPEXPR
// 操作符
:opno 528
// 操作符oid "/"
:opresulttype 23 // 返回的数据类型oid int4
:opretset false
:opcollid 0
:inputcollid 0
:args (
{OPEXPR
// 操作符
:opno 555
// 操作符oid "-"
: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
: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 ">"
: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
}
}
{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;
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);
(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操作。