Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit947d0c8

Browse files
committed
Use appendrel planning logic for top-level UNION ALL structures.
Formerly, we could convert a UNION ALL structure inside a subquery-in-FROMinto an appendrel, as a side effect of pulling up the subquery into itsparent; but top-level UNION ALL always caused use of plan_set_operations().That didn't matter too much because you got an Append-based plan eitherway. However, now that the appendrel code can do things with MergeAppend,it's worthwhile to hack up the top-level case so it also uses appendrels.This is a bit of a stopgap; but going much further than this will requirea major rewrite of the planner's set-operations support, which I'm notprepared to undertake now. For the moment let's grab the low-hanging fruit.
1 parent543d22f commit947d0c8

File tree

3 files changed

+121
-12
lines changed

3 files changed

+121
-12
lines changed

‎src/backend/optimizer/plan/planner.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,12 +341,21 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
341341
inline_set_returning_functions(root);
342342

343343
/*
344-
* Check to see if any subqueries in therangetable can be merged into
344+
* Check to see if any subqueries in thejointree can be merged into
345345
* this query.
346346
*/
347347
parse->jointree= (FromExpr*)
348348
pull_up_subqueries(root, (Node*)parse->jointree,NULL,NULL);
349349

350+
/*
351+
* If this is a simple UNION ALL query, flatten it into an appendrel.
352+
* We do this now because it requires applying pull_up_subqueries to the
353+
* leaf queries of the UNION ALL, which weren't touched above because they
354+
* weren't referenced by the jointree (they will be after we do this).
355+
*/
356+
if (parse->setOperations)
357+
flatten_simple_union_all(root);
358+
350359
/*
351360
* Detect whether any rangetable entries are RTE_JOIN kind; if not, we can
352361
* avoid the expense of doing flatten_join_alias_vars(). Also check for

‎src/backend/optimizer/prep/prepjointree.c

Lines changed: 110 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
*pull_up_sublinks
88
*inline_set_returning_functions
99
*pull_up_subqueries
10+
*flatten_simple_union_all
1011
*do expression preprocessing (including flattening JOIN alias vars)
1112
*reduce_outer_joins
1213
*
@@ -868,11 +869,6 @@ pull_up_simple_union_all(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte)
868869
intrtoffset;
869870
List*rtable;
870871

871-
/*
872-
* Append the subquery rtable entries to upper query.
873-
*/
874-
rtoffset=list_length(root->parse->rtable);
875-
876872
/*
877873
* Append child RTEs to parent rtable.
878874
*
@@ -881,14 +877,15 @@ pull_up_simple_union_all(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte)
881877
* because any such vars must refer to stuff above the level of the query
882878
* we are pulling into.
883879
*/
880+
rtoffset=list_length(root->parse->rtable);
884881
rtable=copyObject(subquery->rtable);
885882
IncrementVarSublevelsUp_rtable(rtable,-1,1);
886883
root->parse->rtable=list_concat(root->parse->rtable,rtable);
887884

888885
/*
889886
* Recursively scan the subquery's setOperations tree and add
890887
* AppendRelInfo nodes for leaf subqueries to the parent's
891-
* append_rel_list.
888+
* append_rel_list. Also apply pull_up_subqueries to the leaf subqueries.
892889
*/
893890
Assert(subquery->setOperations);
894891
pull_up_union_leaf_queries(subquery->setOperations,root,varno,subquery,
@@ -905,14 +902,20 @@ pull_up_simple_union_all(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte)
905902
/*
906903
* pull_up_union_leaf_queries -- recursive guts of pull_up_simple_union_all
907904
*
908-
* Note that setOpQuery is the Query containing the setOp node, whose rtable
909-
* is where to look up the RTE if setOp is a RangeTblRef. This is *not* the
910-
* same as root->parse, which is the top-level Query we are pulling up into.
905+
* Build an AppendRelInfo for each leaf query in the setop tree, and then
906+
* apply pull_up_subqueries to the leaf query.
907+
*
908+
* Note that setOpQuery is the Query containing the setOp node, whose tlist
909+
* contains references to all the setop output columns. When called from
910+
* pull_up_simple_union_all, this is *not* the same as root->parse, which is
911+
* the parent Query we are pulling up into.
911912
*
912913
* parentRTindex is the appendrel parent's index in root->parse->rtable.
913914
*
914-
* The child RTEs have already been copied to the parent. childRToffset
915-
* tells us where in the parent's range table they were copied.
915+
* The child RTEs have already been copied to the parent. childRToffset
916+
* tells us where in the parent's range table they were copied. When called
917+
* from flatten_simple_union_all, childRToffset is 0 since the child RTEs
918+
* were already in root->parse->rtable and no RT index adjustment is needed.
916919
*/
917920
staticvoid
918921
pull_up_union_leaf_queries(Node*setOp,PlannerInfo*root,intparentRTindex,
@@ -1418,6 +1421,102 @@ pullup_replace_vars_callback(Var *var,
14181421
returnnewnode;
14191422
}
14201423

1424+
1425+
/*
1426+
* flatten_simple_union_all
1427+
*Try to optimize top-level UNION ALL structure into an appendrel
1428+
*
1429+
* If a query's setOperations tree consists entirely of simple UNION ALL
1430+
* operations, flatten it into an append relation, which we can process more
1431+
* intelligently than the general setops case. Otherwise, do nothing.
1432+
*
1433+
* In most cases, this can succeed only for a top-level query, because for a
1434+
* subquery in FROM, the parent query's invocation of pull_up_subqueries would
1435+
* already have flattened the UNION via pull_up_simple_union_all. But there
1436+
* are a few cases we can support here but not in that code path, for example
1437+
* when the subquery also contains ORDER BY.
1438+
*/
1439+
void
1440+
flatten_simple_union_all(PlannerInfo*root)
1441+
{
1442+
Query*parse=root->parse;
1443+
SetOperationStmt*topop;
1444+
Node*leftmostjtnode;
1445+
intleftmostRTI;
1446+
RangeTblEntry*leftmostRTE;
1447+
intchildRTI;
1448+
RangeTblEntry*childRTE;
1449+
RangeTblRef*rtr;
1450+
1451+
/* Shouldn't be called unless query has setops */
1452+
topop= (SetOperationStmt*)parse->setOperations;
1453+
Assert(topop&&IsA(topop,SetOperationStmt));
1454+
1455+
/* Can't optimize away a recursive UNION */
1456+
if (root->hasRecursion)
1457+
return;
1458+
1459+
/*
1460+
* Recursively check the tree of set operations. If not all UNION ALL
1461+
* with identical column types, punt.
1462+
*/
1463+
if (!is_simple_union_all_recurse((Node*)topop,parse,topop->colTypes))
1464+
return;
1465+
1466+
/*
1467+
* Locate the leftmost leaf query in the setops tree. The upper query's
1468+
* Vars all refer to this RTE (see transformSetOperationStmt).
1469+
*/
1470+
leftmostjtnode=topop->larg;
1471+
while (leftmostjtnode&&IsA(leftmostjtnode,SetOperationStmt))
1472+
leftmostjtnode= ((SetOperationStmt*)leftmostjtnode)->larg;
1473+
Assert(leftmostjtnode&&IsA(leftmostjtnode,RangeTblRef));
1474+
leftmostRTI= ((RangeTblRef*)leftmostjtnode)->rtindex;
1475+
leftmostRTE=rt_fetch(leftmostRTI,parse->rtable);
1476+
Assert(leftmostRTE->rtekind==RTE_SUBQUERY);
1477+
1478+
/*
1479+
* Make a copy of the leftmost RTE and add it to the rtable. This copy
1480+
* will represent the leftmost leaf query in its capacity as a member
1481+
* of the appendrel. The original will represent the appendrel as a
1482+
* whole. (We must do things this way because the upper query's Vars
1483+
* have to be seen as referring to the whole appendrel.)
1484+
*/
1485+
childRTE=copyObject(leftmostRTE);
1486+
parse->rtable=lappend(parse->rtable,childRTE);
1487+
childRTI=list_length(parse->rtable);
1488+
1489+
/* Modify the setops tree to reference the child copy */
1490+
((RangeTblRef*)leftmostjtnode)->rtindex=childRTI;
1491+
1492+
/* Modify the formerly-leftmost RTE to mark it as an appendrel parent */
1493+
leftmostRTE->inh= true;
1494+
1495+
/*
1496+
* Form a RangeTblRef for the appendrel, and insert it into FROM. The top
1497+
* Query of a setops tree should have had an empty FromClause initially.
1498+
*/
1499+
rtr=makeNode(RangeTblRef);
1500+
rtr->rtindex=leftmostRTI;
1501+
Assert(parse->jointree->fromlist==NIL);
1502+
parse->jointree->fromlist=list_make1(rtr);
1503+
1504+
/*
1505+
* Now pretend the query has no setops. We must do this before trying
1506+
* to do subquery pullup, because of Assert in pull_up_simple_subquery.
1507+
*/
1508+
parse->setOperations=NULL;
1509+
1510+
/*
1511+
* Build AppendRelInfo information, and apply pull_up_subqueries to the
1512+
* leaf queries of the UNION ALL. (We must do that now because they
1513+
* weren't previously referenced by the jointree, and so were missed by
1514+
* the main invocation of pull_up_subqueries.)
1515+
*/
1516+
pull_up_union_leaf_queries((Node*)topop,root,leftmostRTI,parse,0);
1517+
}
1518+
1519+
14211520
/*
14221521
* reduce_outer_joins
14231522
*Attempt to reduce outer joins to plain inner joins.

‎src/include/optimizer/prep.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ extern void inline_set_returning_functions(PlannerInfo *root);
2626
externNode*pull_up_subqueries(PlannerInfo*root,Node*jtnode,
2727
JoinExpr*lowest_outer_join,
2828
AppendRelInfo*containing_appendrel);
29+
externvoidflatten_simple_union_all(PlannerInfo*root);
2930
externvoidreduce_outer_joins(PlannerInfo*root);
3031
externRelidsget_relids_in_jointree(Node*jtnode,boolinclude_joins);
3132
externRelidsget_relids_for_join(PlannerInfo*root,intjoinrelid);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp