PostgreSQL 原始碼解讀(30)- 查詢語句#15(查詢優化-扁平化處理UNION ALL)
本文簡單介紹了PG查詢優化中對頂層UNION ALL語句進行的扁平化(flatten)處理過程。扁平化處理的目的是把UNION ALL的集合操作轉換為Append Relation以進行優化處理。
一、測試指令碼
測試指令碼:
testdb=# select a.dwbh
from t_dwxx a
union all
select b.dwbh
from t_grxx b
union all
select c.grbh
from t_jfxx c;
查詢樹如下圖所示:
二、原始碼解讀
/*
* flatten_simple_union_all
* Try to optimize top-level UNION ALL structure into an appendrel
*
* If a query's setOperations tree consists entirely of simple UNION ALL
* operations, flatten it into an append relation, which we can process more
* intelligently than the general setops case. Otherwise, do nothing.
*
* In most cases, this can succeed only for a top-level query, because for a
* subquery in FROM, the parent query's invocation of pull_up_subqueries would
* already have flattened the UNION via pull_up_simple_union_all. But there
* are a few cases we can support here but not in that code path, for example
* when the subquery also contains ORDER BY.
*/
void
flatten_simple_union_all(PlannerInfo *root)
{
Query *parse = root->parse;//查詢樹
SetOperationStmt *topop;//集合操作語句
Node *leftmostjtnode;//最左邊節點
int leftmostRTI;//最左邊節點對應的RTI(rtable中的位置,即rtindex)
RangeTblEntry *leftmostRTE;//最左邊節點對應的RTE
int childRTI;//child的RTI
RangeTblEntry *childRTE;//子RTE
RangeTblRef *rtr;//RTR
/* Shouldn't be called unless query has setops */
topop = castNode(SetOperationStmt, parse->setOperations);//獲取集合操作語句
Assert(topop);
/* Can't optimize away a recursive UNION */
if (root->hasRecursion)
return;//不支援遞迴UNION
/*
* Recursively check the tree of set operations. If not all UNION ALL
* with identical column types, punt.
*/
if (!is_simple_union_all_recurse((Node *) topop, parse, topop->colTypes))
return;//不是簡單的UNION ALL,返回
/*
* Locate the leftmost leaf query in the setops tree. The upper query's
* Vars all refer to this RTE (see transformSetOperationStmt).
*/
leftmostjtnode = topop->larg;//左邊的child
while (leftmostjtnode && IsA(leftmostjtnode, SetOperationStmt))
leftmostjtnode = ((SetOperationStmt *) leftmostjtnode)->larg;//獲取最左邊的葉子節點(非SetOperationStmt)
Assert(leftmostjtnode && IsA(leftmostjtnode, RangeTblRef));
leftmostRTI = ((RangeTblRef *) leftmostjtnode)->rtindex;//最左邊節點的RTI
leftmostRTE = rt_fetch(leftmostRTI, parse->rtable);//從rtable中獲取leftmostRTI指向的RTE
Assert(leftmostRTE->rtekind == RTE_SUBQUERY);//該RTE一定是子查詢
/*
* Make a copy of the leftmost RTE and add it to the rtable. This copy
* will represent the leftmost leaf query in its capacity as a member of
* the appendrel. The original will represent the appendrel as a whole.
* (We must do things this way because the upper query's Vars have to be
* seen as referring to the whole appendrel.)
*/
childRTE = copyObject(leftmostRTE);//Make a copy
parse->rtable = lappend(parse->rtable, childRTE);//把RTE追加到上層rtable
childRTI = list_length(parse->rtable);//相應的rtindex
/* Modify the setops tree to reference the child copy */
((RangeTblRef *) leftmostjtnode)->rtindex = childRTI;//調整RTR的rtindex
/* Modify the formerly-leftmost RTE to mark it as an appendrel parent */
leftmostRTE->inh = true;
/*
* Form a RangeTblRef for the appendrel, and insert it into FROM. The top
* Query of a setops tree should have had an empty FromClause initially.
*/
rtr = makeNode(RangeTblRef);//構造一個RTR
rtr->rtindex = leftmostRTI;//rtindex=最左邊節點的rtindex
Assert(parse->jointree->fromlist == NIL);//Query的jointree(FromExpr)->fromlist應為NULL
parse->jointree->fromlist = list_make1(rtr);//把RTR放到jointree的fromlist中
/*
* Now pretend the query has no setops. We must do this before trying to
* do subquery pullup, because of Assert in pull_up_simple_subquery.
*/
parse->setOperations = NULL;//集合操作設定為NULL
/*
* Build AppendRelInfo information, and apply pull_up_subqueries to the
* leaf queries of the UNION ALL. (We must do that now because they
* weren't previously referenced by the jointree, and so were missed by
* the main invocation of pull_up_subqueries.)
*/
pull_up_union_leaf_queries((Node *) topop, root, leftmostRTI, parse, 0);
}
/*
* pull_up_union_leaf_queries -- recursive guts of pull_up_simple_union_all
*
* Build an AppendRelInfo for each leaf query in the setop tree, and then
* apply pull_up_subqueries to the leaf query.
*
* Note that setOpQuery is the Query containing the setOp node, whose tlist
* contains references to all the setop output columns. When called from
* pull_up_simple_union_all, this is *not* the same as root->parse, which is
* the parent Query we are pulling up into.
*
* parentRTindex is the appendrel parent's index in root->parse->rtable.
*
* The child RTEs have already been copied to the parent. childRToffset
* tells us where in the parent's range table they were copied. When called
* from flatten_simple_union_all, childRToffset is 0 since the child RTEs
* were already in root->parse->rtable and no RT index adjustment is needed.
*/
static void
pull_up_union_leaf_queries(Node *setOp, PlannerInfo *root, int parentRTindex,
Query *setOpQuery, int childRToffset)
{
if (IsA(setOp, RangeTblRef))//RTR
{
RangeTblRef *rtr = (RangeTblRef *) setOp;
int childRTindex;
AppendRelInfo *appinfo;
/*
* Calculate the index in the parent's range table
*/
childRTindex = childRToffset + rtr->rtindex;
/*
* Build a suitable AppendRelInfo, and attach to parent's list.
*/
appinfo = makeNode(AppendRelInfo);//構造AppendRelInfo
appinfo->parent_relid = parentRTindex;
appinfo->child_relid = childRTindex;
appinfo->parent_reltype = InvalidOid;
appinfo->child_reltype = InvalidOid;
make_setop_translation_list(setOpQuery, childRTindex,
&appinfo->translated_vars);//把相關的Vars新增到AppendRelInfo中
appinfo->parent_reloid = InvalidOid;
root->append_rel_list = lappend(root->append_rel_list, appinfo);//新增到PlannerInfo中
/*
* Recursively apply pull_up_subqueries to the new child RTE. (We
* must build the AppendRelInfo first, because this will modify it.)
* Note that we can pass NULL for containing-join info even if we're
* actually under an outer join, because the child's expressions
* aren't going to propagate up to the join. Also, we ignore the
* possibility that pull_up_subqueries_recurse() returns a different
* jointree node than what we pass it; if it does, the important thing
* is that it replaced the child relid in the AppendRelInfo node.
*/
rtr = makeNode(RangeTblRef);
rtr->rtindex = childRTindex;
(void) pull_up_subqueries_recurse(root, (Node *) rtr,
NULL, NULL, appinfo, false);//提升子查詢
}
else if (IsA(setOp, SetOperationStmt))//型別為SetOperationStmt
{
SetOperationStmt *op = (SetOperationStmt *) setOp;
/* Recurse to reach leaf queries */
pull_up_union_leaf_queries(op->larg, root, parentRTindex, setOpQuery,
childRToffset);//左Child
pull_up_union_leaf_queries(op->rarg, root, parentRTindex, setOpQuery,
childRToffset);//右Child
}
else
{
elog(ERROR, "unrecognized node type: %d",
(int) nodeTag(setOp));
}
}
三、基礎資訊
資料結構/巨集定義
1、SetOperationStmt
/* ----------------------
* Set Operation node for post-analysis query trees
*
* After parse analysis, a SELECT with set operations is represented by a
* top-level Query node containing the leaf SELECTs as subqueries in its
* range table. Its setOperations field shows the tree of set operations,
* with leaf SelectStmt nodes replaced by RangeTblRef nodes, and internal
* nodes replaced by SetOperationStmt nodes. Information about the output
* column types is added, too. (Note that the child nodes do not necessarily
* produce these types directly, but we've checked that their output types
* can be coerced to the output column type.) Also, if it's not UNION ALL,
* information about the types' sort/group semantics is provided in the form
* of a SortGroupClause list (same representation as, eg, DISTINCT).
* The resolved common column collations are provided too; but note that if
* it's not UNION ALL, it's okay for a column to not have a common collation,
* so a member of the colCollations list could be InvalidOid even though the
* column has a collatable type.
* ----------------------
*/
typedef enum SetOperation
{
SETOP_NONE = 0,
SETOP_UNION,
SETOP_INTERSECT,
SETOP_EXCEPT
} SetOperation;
typedef struct SetOperationStmt
{
NodeTag type;//節點型別
SetOperation op; /* 操作型別,type of set op */
bool all; /* 是否UNION ALL,ALL specified? */
Node *larg; /* left child,左Child,型別為RTR或SetOperationStmt */
Node *rarg; /* right child,右Child,型別為RTR或SetOperationStmt */
/* Eventually add fields for CORRESPONDING spec here */
/* Fields derived during parse analysis: */
List *colTypes; /* OID list of output column type OIDs,資料列型別 */
List *colTypmods; /* integer list of output column typmods,精度/刻度資訊 */
List *colCollations; /* OID list of output column collation OIDs,collation資訊*/
List *groupClauses; /* a list of SortGroupClause's,SortGroup語句*/
/* groupClauses is NIL if UNION ALL, but must be set otherwise */
} SetOperationStmt;
依賴的函式
1、make_setop_translation_list
/*
* make_setop_translation_list
* Build the list of translations from parent Vars to child Vars for
* a UNION ALL member. (At this point it's just a simple list of
* referencing Vars, but if we succeed in pulling up the member
* subquery, the Vars will get replaced by pulled-up expressions.)
*/
static void
make_setop_translation_list(Query *query, Index newvarno,
List **translated_vars)
{
List *vars = NIL;
ListCell *l;
foreach(l, query->targetList)
{
TargetEntry *tle = (TargetEntry *) lfirst(l);
if (tle->resjunk)
continue;
vars = lappend(vars, makeVarFromTargetEntry(newvarno, tle));
}
*translated_vars = vars;
}
四、跟蹤分析
測試指令碼見上,啟動gdb跟蹤:
(gdb) b flatten_simple_union_all
Breakpoint 1 at 0x77f964: file prepjointree.c, line 2355.
(gdb) c
Continuing.
Breakpoint 1, flatten_simple_union_all (root=0x16a6338) at prepjointree.c:2355
2355 Query *parse = root->parse;
#輸入引數
#1.root,見前面章節,root->parse見先前小節的圖(查詢樹)
...
#獲取最左邊的葉子節點(型別為RTR)
2384 while (leftmostjtnode && IsA(leftmostjtnode, SetOperationStmt))
(gdb)
2387 leftmostRTI = ((RangeTblRef *) leftmostjtnode)->rtindex;
(gdb) p *leftmostjtnode
$9 = {type = T_RangeTblRef}
...
#新增到root->rtable中
(gdb) n
2399 parse->rtable = lappend(parse->rtable, childRTE);
(gdb)
2400 childRTI = list_length(parse->rtable);
#原來的rtable為3個子查詢,在最後面新增1個
(gdb) p *parse->rtable
$12 = {type = T_List, length = 4, head = 0x15e9dc8, tail = 0x16b09d0}
(gdb) p leftmostRTI
$19 = 1
#copy了一份"子查詢",放在rtable的最後面
(gdb) p *((RangeTblEntry *)parse->rtable->head->next->next->next->data.ptr_value)->alias
$20 = {type = T_Alias, aliasname = 0x16b08d8 "*SELECT* 1", colnames = 0x0}
(gdb) p *((RangeTblEntry *)parse->rtable->head->data.ptr_value)->alias
$21 = {type = T_Alias, aliasname = 0x15e9cd0 "*SELECT* 1", colnames = 0x0}
(gdb)
#構造RTR(rtindex=1),放在jointree的fromlist中
2406 leftmostRTE->inh = true;
(gdb)
2412 rtr = makeNode(RangeTblRef);
(gdb)
2413 rtr->rtindex = leftmostRTI;
(gdb)
2415 parse->jointree->fromlist = list_make1(rtr);
(gdb) p *rtr
$23 = {type = T_RangeTblRef, rtindex = 1}
(gdb) p *(RangeTblRef *) leftmostjtnode
$24 = {type = T_RangeTblRef, rtindex = 4}
(gdb) p *parse->jointree->fromlist
$26 = {type = T_List, length = 1, head = 0x16b0a08, tail = 0x16b0a08}
#進入pull_up_union_leaf_queries
(gdb) n
2429 pull_up_union_leaf_queries((Node *) topop, root, leftmostRTI, parse, 0);
(gdb) step
pull_up_union_leaf_queries (setOp=0x15c59c8, root=0x16a6338, parentRTindex=1, setOpQuery=0x15c58b8, childRToffset=0)
at prepjointree.c:1344
1344 if (IsA(setOp, RangeTblRef))
#輸入引數
#1.setOp,SetOperationStmt
#2.root,同flatten_simple_union_all
#3.leftmostRTI=1,最左邊節點的rtindex
#4.parse,查詢樹
#5.childRToffset,RT的初始偏移量
1344 if (IsA(setOp, RangeTblRef))
#setOp為SetOperationStmt型別,遞迴呼叫SetOperationStmt->larg->larg
(gdb) n
1383 else if (IsA(setOp, SetOperationStmt))
...
1388 pull_up_union_leaf_queries(op->larg, root, parentRTindex, setOpQuery,
(gdb) step
pull_up_union_leaf_queries (setOp=0x15c5a18, root=0x16a6338, parentRTindex=1, setOpQuery=0x15c58b8, childRToffset=0)
at prepjointree.c:1344
1344 if (IsA(setOp, RangeTblRef))
1344 if (IsA(setOp, RangeTblRef))
(gdb) n
1383 else if (IsA(setOp, SetOperationStmt))
(gdb)
1385 SetOperationStmt *op = (SetOperationStmt *) setOp;
(gdb)
1388 pull_up_union_leaf_queries(op->larg, root, parentRTindex, setOpQuery,
(gdb) step
pull_up_union_leaf_queries (setOp=0x15e9e18, root=0x16a6338, parentRTindex=1, setOpQuery=0x15c58b8, childRToffset=0)
at prepjointree.c:1344
1344 if (IsA(setOp, RangeTblRef))
...
1346 RangeTblRef *rtr = (RangeTblRef *) setOp;
(gdb)
1353 childRTindex = childRToffset + rtr->rtindex;
(gdb)
1358 appinfo = makeNode(AppendRelInfo);
#最左邊的RTR在flatten_simple_union_all中已調整為4
(gdb) p *rtr
$27 = {type = T_RangeTblRef, rtindex = 4}
(gdb) p childRTindex
$28 = 4
#構造AppendRelInfo,插入到root->append_rel_list中
(gdb) n
1359 appinfo->parent_relid = parentRTindex;
...
#進入pull_up_subqueries_recurse
(gdb) step
pull_up_subqueries_recurse (root=0x16a6338, jtnode=0x16b0b98, lowest_outer_join=0x0, lowest_nulling_outer_join=0x0,
containing_appendrel=0x16b0a58, deletion_ok=false) at prepjointree.c:680
680 if (IsA(jtnode, RangeTblRef))
#查詢樹的rtable中增加RTE(RTE_RELATION)
(gdb) p *parse->rtable
$47 = {type = T_List, length = 5, head = 0x15e9dc8, tail = 0x16b0cf0}
(gdb) p *(RangeTblEntry *)parse->rtable->tail->data.ptr_value
$49 = {type = T_RangeTblEntry, rtekind = RTE_RELATION, relid = 16394, relkind = 114 'r', tablesample = 0x0, subquery = 0x0,
security_barrier = false, jointype = JOIN_INNER, joinaliasvars = 0x0, functions = 0x0, funcordinality = false,
tablefunc = 0x0, values_lists = 0x0, ctename = 0x0, ctelevelsup = 0, self_reference = false, coltypes = 0x0,
coltypmods = 0x0, colcollations = 0x0, enrname = 0x0, enrtuples = 0, alias = 0x16b0e20, eref = 0x16b0e68,
lateral = false, inh = true, inFromCl = true, requiredPerms = 2, checkAsUser = 0, selectedCols = 0x16b0fe8,
insertedCols = 0x0, updatedCols = 0x0, securityQuals = 0x0}
(gdb) n
pull_up_subqueries_recurse (root=0x16a6338, jtnode=0x16b0b98, lowest_outer_join=0x0, lowest_nulling_outer_join=0x0,
containing_appendrel=0x16b0a58, deletion_ok=false) at prepjointree.c:853
853 }
(gdb)
pull_up_union_leaf_queries (setOp=0x15e9e18, root=0x16a6338, parentRTindex=1, setOpQuery=0x15c58b8, childRToffset=0)
at prepjointree.c:1398
1398 }
(gdb) n
#處理SetOperationStmt->larg(SetOperationStmt)->rarg
pull_up_union_leaf_queries (setOp=0x15c5a18, root=0x16a6338, parentRTindex=1, setOpQuery=0x15c58b8, childRToffset=0)
at prepjointree.c:1390
1390 pull_up_union_leaf_queries(op->rarg, root, parentRTindex, setOpQuery,
(gdb)
1398 }
(gdb)
#處理SetOperationStmt->rarg
pull_up_union_leaf_queries (setOp=0x15c59c8, root=0x16a6338, parentRTindex=1, setOpQuery=0x15c58b8, childRToffset=0)
at prepjointree.c:1390
1390 pull_up_union_leaf_queries(op->rarg, root, parentRTindex, setOpQuery,
(gdb)
1398 }
(gdb)
flatten_simple_union_all (root=0x16a6338) at prepjointree.c:2430
2430 }
#
(gdb) p *root
$54 = {type = T_PlannerInfo, parse = 0x15c58b8, glob = 0x15eb8b0, query_level = 1, parent_root = 0x0, plan_params = 0x0,
outer_params = 0x0, simple_rel_array = 0x0, simple_rel_array_size = 0, simple_rte_array = 0x0, all_baserels = 0x0,
nullable_baserels = 0x0, join_rel_list = 0x0, join_rel_hash = 0x0, join_rel_level = 0x0, join_cur_level = 0,
init_plans = 0x0, cte_plan_ids = 0x0, multiexpr_params = 0x0, eq_classes = 0x0, canon_pathkeys = 0x0,
left_join_clauses = 0x0, right_join_clauses = 0x0, full_join_clauses = 0x0, join_info_list = 0x0,
append_rel_list = 0x16b0b68, rowMarks = 0x0, placeholder_list = 0x0, fkey_list = 0x0, query_pathkeys = 0x0,
group_pathkeys = 0x0, window_pathkeys = 0x0, distinct_pathkeys = 0x0, sort_pathkeys = 0x0, part_schemes = 0x0,
initial_rels = 0x0, upper_rels = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, upper_targets = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0}, processed_tlist = 0x0, grouping_map = 0x0, minmax_aggs = 0x0, planner_cxt = 0x15c3e90, total_table_pages = 0,
tuple_fraction = 0, limit_tuples = 0, qual_security_level = 0, inhTargetKind = INHKIND_NONE, hasJoinRTEs = false,
hasLateralRTEs = false, hasDeletedRTEs = false, hasHavingQual = false, hasPseudoConstantQuals = false,
hasRecursion = false, wt_param_id = -1, non_recursive_path = 0x0, curOuterRels = 0x0, curOuterParams = 0x0,
join_search_private = 0x0, partColsUpdated = false}
(gdb) p *root->append_rel_list
$55 = {type = T_List, length = 3, head = 0x16b0b48, tail = 0x16b2790}
(gdb) p root->parse
$56 = (Query *) 0x15c58b8
(gdb) p *root->parse
$57 = {type = T_Query, commandType = CMD_SELECT, querySource = QSRC_ORIGINAL, queryId = 0, canSetTag = true,
utilityStmt = 0x0, resultRelation = 0, hasAggs = false, hasWindowFuncs = false, hasTargetSRFs = false,
hasSubLinks = false, hasDistinctOn = false, hasRecursive = false, hasModifyingCTE = false, hasForUpdate = false,
hasRowSecurity = false, cteList = 0x0, rtable = 0x15e9de8, jointree = 0x15eb880, targetList = 0x16b3348,
override = OVERRIDING_NOT_SET, onConflict = 0x0, returningList = 0x0, groupClause = 0x0, groupingSets = 0x0,
havingQual = 0x0, windowClause = 0x0, distinctClause = 0x0, sortClause = 0x0, limitOffset = 0x0, limitCount = 0x0,
rowMarks = 0x0, setOperations = 0x0, constraintDeps = 0x0, withCheckOptions = 0x0, stmt_location = 0, stmt_len = 104}
#rtable中已有7個元素,其中第4個是子查詢,第5-7個是實際的RTE_RELATION(relid分別是16394/16397/16400)
(gdb) p *root->parse->rtable
$58 = {type = T_List, length = 7, head = 0x15e9dc8, tail = 0x16b2908}
(gdb)
#第4個元素
(gdb) p *((RangeTblEntry *)root->parse->rtable->head->next->next->next->data.ptr_value)
$80 = {type = T_RangeTblEntry, rtekind = RTE_SUBQUERY, relid = 0, relkind = 0 '\000', tablesample = 0x0,
subquery = 0x15c57a8, security_barrier = false, jointype = JOIN_INNER, joinaliasvars = 0x0, functions = 0x0,
funcordinality = false, tablefunc = 0x0, values_lists = 0x0, ctename = 0x0, ctelevelsup = 0, self_reference = false,
coltypes = 0x0, coltypmods = 0x0, colcollations = 0x0, enrname = 0x0, enrtuples = 0, alias = 0x16b08a8, eref = 0x16b08f8,
lateral = false, inh = false, inFromCl = false, requiredPerms = 0, checkAsUser = 0, selectedCols = 0x0,
insertedCols = 0x0, updatedCols = 0x0, securityQuals = 0x0}
(gdb) p *((RangeTblEntry *)root->parse->rtable->head->next->next->next->data.ptr_value)->eref
$81 = {type = T_Alias, aliasname = 0x16b0928 "*SELECT* 1", colnames = 0x16b0948}
#第5個元素
(gdb) p *((RangeTblEntry *)root->parse->rtable->head->next->next->next->next->data.ptr_value)
$82 = {type = T_RangeTblEntry, rtekind = RTE_RELATION, relid = 16394, relkind = 114 'r', tablesample = 0x0, subquery = 0x0,
security_barrier = false, jointype = JOIN_INNER, joinaliasvars = 0x0, functions = 0x0, funcordinality = false,
tablefunc = 0x0, values_lists = 0x0, ctename = 0x0, ctelevelsup = 0, self_reference = false, coltypes = 0x0,
coltypmods = 0x0, colcollations = 0x0, enrname = 0x0, enrtuples = 0, alias = 0x16b0e20, eref = 0x16b0e68,
lateral = false, inh = true, inFromCl = true, requiredPerms = 2, checkAsUser = 0, selectedCols = 0x16b0fe8,
insertedCols = 0x0, updatedCols = 0x0, securityQuals = 0x0}
(gdb) p *((RangeTblEntry *)root->parse->rtable->head->next->next->next->next->data.ptr_value)->eref
$83 = {type = T_Alias, aliasname = 0x16b0e98 "a", colnames = 0x16b0eb0}
#root->append_rel_list中有3個元素,分別對應rtable中的5-7
(gdb) p *root->append_rel_list
$69 = {type = T_List, length = 3, head = 0x16b0b48, tail = 0x16b2790}
(gdb) p *(Node *)root->append_rel_list->head->data.ptr_value
$70 = {type = T_AppendRelInfo}
(gdb) p *(AppendRelInfo *)root->append_rel_list->head->data.ptr_value
$71 = {type = T_AppendRelInfo, parent_relid = 1, child_relid = 5, parent_reltype = 0, child_reltype = 0,
translated_vars = 0x16b33e8, parent_reloid = 0}
#查詢樹的jointree
(gdb) p *root->parse->jointree
$87 = {type = T_FromExpr, fromlist = 0x16b0a28, quals = 0x0}
(gdb) p *root->parse->jointree->fromlist
$88 = {type = T_List, length = 1, head = 0x16b0a08, tail = 0x16b0a08}
(gdb) p *(RangeTblRef *)root->parse->jointree->fromlist->head->data.ptr_value
$90 = {type = T_RangeTblRef, rtindex = 1}
(gdb) n
subquery_planner (glob=0x15eb8b0, parse=0x15c58b8, parent_root=0x0, hasRecursion=false, tuple_fraction=0) at planner.c:680
680 root->hasJoinRTEs = false;
#DONE!
優化後的查詢樹如下圖所示:
五、小結
UNION ALL優化過程:把集合操作扁平化為AppendRelInfo,通過增加AppendRelInfo、修改rtable等方式實現。
參考資料:
prepjointree.c
list.c
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/6906/viewspace-2374883/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- PostgreSQL 原始碼解讀(33)- 查詢語句#18(查詢優化-表示式預處理#3)SQL原始碼優化
- PostgreSQL 原始碼解讀(34)- 查詢語句#19(查詢優化-表示式預處理#4)SQL原始碼優化
- PostgreSQL 原始碼解讀(31)- 查詢語句#16(查詢優化-表示式預處理#1)SQL原始碼優化
- PostgreSQL 原始碼解讀(32)- 查詢語句#17(查詢優化-表示式預處理#2)SQL原始碼優化
- PostgreSQL 原始碼解讀(25)- 查詢語句#10(查詢優化概覽)SQL原始碼優化
- PostgreSQL 原始碼解讀(17)- 查詢語句#2(查詢優化基礎)SQL原始碼優化
- PostgreSQL 原始碼解讀(29)- 查詢語句#14(查詢優化-上拉子查詢)SQL原始碼優化
- PostgreSQL 原始碼解讀(36)- 查詢語句#21(查詢優化-消除外連線)SQL原始碼優化
- PostgreSQL 原始碼解讀(37)- 查詢語句#22(查詢優化-grouping_plan...SQL原始碼優化
- PostgreSQL 原始碼解讀(24)- 查詢語句#9(查詢重寫)SQL原始碼
- PostgreSQL 原始碼解讀(35)- 查詢語句#20(查詢優化-簡化Having和Grou...SQL原始碼優化
- PostgreSQL 原始碼解讀(26)- 查詢語句#11(查詢優化-上拉子連結#1)SQL原始碼優化
- PostgreSQL 原始碼解讀(27)- 查詢語句#12(查詢優化-上拉子連結#2)SQL原始碼優化
- PostgreSQL 原始碼解讀(28)- 查詢語句#13(查詢優化-上拉子連結#3)SQL原始碼優化
- PostgreSQL 原始碼解讀(20)- 查詢語句#5(查詢樹Query詳解)SQL原始碼
- PostgreSQL 原始碼解讀(18)- 查詢語句#3(SQL Parse)SQL原始碼
- PostgreSQL 原始碼解讀(19)- 查詢語句#4(ParseTree詳解)SQL原始碼
- PostgreSQL 原始碼解讀(45)- 查詢語句#30(query_planner函式#6)SQL原始碼函式
- PostgreSQL 原始碼解讀(83)- 查詢語句#68(PortalStart函式)SQL原始碼函式
- PostgreSQL 原始碼解讀(42)- 查詢語句#27(等價類)SQL原始碼
- PostgreSQL 原始碼解讀(74)- 查詢語句#59(Review - subquery_...SQL原始碼View
- PostgreSQL 原始碼解讀(75)- 查詢語句#60(Review - standard_...SQL原始碼View
- PostgreSQL 原始碼解讀(90)- 查詢語句#75(ExecHashJoin函式#1)SQL原始碼函式
- PostgreSQL 原始碼解讀(91)- 查詢語句#76(ExecHashJoin函式#2)SQL原始碼函式
- PostgreSQL 原始碼解讀(93)- 查詢語句#77(ExecHashJoin函式#3)SQL原始碼函式
- PostgreSQL 原始碼解讀(81)- 查詢語句#66(Review - exec_simp...SQL原始碼View
- PostgreSQL 原始碼解讀(84)- 查詢語句#69(PortalStart->InitP...SQL原始碼
- PostgreSQL 原始碼解讀(85)- 查詢語句#70(PortalRun->InitPla...SQL原始碼
- PostgreSQL 原始碼解讀(86)- 查詢語句#71(PortalRun->PortalR...SQL原始碼
- PostgreSQL 原始碼解讀(50)- 查詢語句#35(Optimizer Review#1)SQL原始碼View
- PostgreSQL 原始碼解讀(51)- 查詢語句#36(Optimizer Review#2)SQL原始碼View
- PostgreSQL 原始碼解讀(65)- 查詢語句#50(make_one_rel函式#15-...SQL原始碼函式
- PostgreSQL 原始碼解讀(23)- 查詢語句#8(PlannedStmt與QUERY P...SQL原始碼
- PostgreSQL 原始碼解讀(87)- 查詢語句#72(PortalRunSelect->E...SQL原始碼
- PostgreSQL 原始碼解讀(21)- 查詢語句#6(PlannedStmt詳解-跟蹤分析)SQL原始碼
- 查詢集合操作union與union all
- 效能優化查詢語句優化
- PostgreSQL 原始碼解讀(16)- 查詢語句#1(基礎:關係代數)SQL原始碼