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