Sorry, I missed to attach file.
> This is cont'd from CF3.
>
> http://www.postgresql.org/message-id/[email protected]
>
> The issue in brief is that UNION is never flattened differently
> to UNION ALL so UNION cannot make use of index scan even if
> usable.
>
> This patch flattens UNION likewise currently did for UNION ALL.
>
> This patch needs another 'UNION ALL' patch and further gain with
> even another 'Widening application of indices' patch. ('Ready for
> Commit' now in CF3..)
>
> http://www.postgresql.org/message-id/[email protected]
> http://www.postgresql.org/message-id/[email protected]
>
>
> You can see the detailed outlines in the message at here,
>
> http://www.postgresql.org/message-id/[email protected]
>
> The attached patche is rebased to current 9.4dev HEAD and make
> check at the topmost directory and src/test/isolation are passed
> without error.
regards,
--
Kyotaro Horiguchi
NTT Open Source Software Center
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 1da4b2f..e89f8b3 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -353,13 +353,14 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
pull_up_subqueries(root, (Node *) parse->jointree);
/*
- * If this is a simple UNION ALL query, flatten it into an appendrel. We
- * do this now because it requires applying pull_up_subqueries to the leaf
- * queries of the UNION ALL, which weren't touched above because they
- * weren't referenced by the jointree (they will be after we do this).
+ * If this is a simple UNION/UNION ALL query, flatten it into an
+ * appendrel. We do this now because it requires applying
+ * pull_up_subqueries to the leaf queries of the UNION/UNION ALL, which
+ * weren't touched above because they weren't referenced by the jointree
+ * (they will be after we do this).
*/
if (parse->setOperations)
- flatten_simple_union_all(root);
+ flatten_simple_union(root);
/*
* Detect whether any rangetable entries are RTE_JOIN kind; if not, we can
diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c
index 1c6083b..04bba48 100644
--- a/src/backend/optimizer/prep/prepjointree.c
+++ b/src/backend/optimizer/prep/prepjointree.c
@@ -32,6 +32,7 @@
#include "optimizer/subselect.h"
#include "optimizer/tlist.h"
#include "parser/parse_relation.h"
+#include "parser/parse_clause.h"
#include "parser/parsetree.h"
#include "rewrite/rewriteManip.h"
@@ -81,8 +82,8 @@ static void make_setop_translation_list(Query *query, Index newvarno,
static bool is_simple_subquery(Query *subquery, RangeTblEntry *rte,
JoinExpr *lowest_outer_join);
static bool is_simple_union_all(Query *subquery);
-static bool is_simple_union_all_recurse(Node *setOp, Query *setOpQuery,
- List *colTypes);
+static bool is_simple_union_recurse(SetOperationStmt *topop, Node *setOp,
+ Query *setOpQuery, List *colTypes);
static bool is_safe_append_member(Query *subquery);
static bool jointree_contains_lateral_outer_refs(Node *jtnode, bool restricted,
Relids safe_upper_varnos);
@@ -1440,12 +1441,14 @@ is_simple_union_all(Query *subquery)
return false;
/* Recursively check the tree of set operations */
- return is_simple_union_all_recurse((Node *) topop, subquery,
- topop->colTypes);
+ if (topop->op != SETOP_UNION || !topop->all) return false;
+ return is_simple_union_recurse(topop, (Node *) topop, subquery,
+ topop->colTypes);
}
static bool
-is_simple_union_all_recurse(Node *setOp, Query *setOpQuery, List *colTypes)
+is_simple_union_recurse(SetOperationStmt *topop, Node *setOp,
+ Query *setOpQuery, List *colTypes)
{
if (IsA(setOp, RangeTblRef))
{
@@ -1463,13 +1466,16 @@ is_simple_union_all_recurse(Node *setOp, Query *setOpQuery, List *colTypes)
{
SetOperationStmt *op = (SetOperationStmt *) setOp;
- /* Must be UNION ALL */
- if (op->op != SETOP_UNION || !op->all)
+ /* All SetOps under topop are UNION and ->all is same to topop */
+ if (op->op != SETOP_UNION || op->all != topop->all)
return false;
/* Recurse to check inputs */
- return is_simple_union_all_recurse(op->larg, setOpQuery, colTypes) &&
- is_simple_union_all_recurse(op->rarg, setOpQuery, colTypes);
+ return
+ is_simple_union_recurse(topop, op->larg,
+ setOpQuery, colTypes) &&
+ is_simple_union_recurse(topop, op->rarg,
+ setOpQuery, colTypes);
}
else
{
@@ -1908,23 +1914,22 @@ pullup_replace_vars_subquery(Query *query,
NULL);
}
-
/*
* flatten_simple_union_all
- * Try to optimize top-level UNION ALL structure into an appendrel
+ * Try to optimize top-level UNION/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.
+ * If a query's setOperations tree consists entirely of simple UNION and 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
+ * already have flattened the UNION ALL 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)
+flatten_simple_union(PlannerInfo *root)
{
Query *parse = root->parse;
SetOperationStmt *topop;
@@ -1944,10 +1949,18 @@ flatten_simple_union_all(PlannerInfo *root)
return;
/*
- * Recursively check the tree of set operations. If not all UNION ALL
+ * If topop is not UNION (not likey), punt. Also for UNION(not ALL)
+ * without sortClause or already having distinctClause.
+ */
+ if (topop->op != SETOP_UNION ||
+ (!topop->all && (!parse->sortClause || parse->distinctClause )))
+ return;
+
+ /*
+ * 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))
+ if (!is_simple_union_recurse(topop, (Node *) topop, parse, topop->colTypes))
return;
/*
@@ -1995,6 +2008,16 @@ flatten_simple_union_all(PlannerInfo *root)
parse->setOperations = NULL;
/*
+ * We can create distinctClause using transformDistinctClause() with
+ * pstate == NULL.
+ */
+ if (!topop->all)
+ parse->distinctClause =
+ transformDistinctClause(NULL,
+ &parse->targetList, parse->sortClause,
+ false);
+
+ /*
* 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
diff --git a/src/include/optimizer/prep.h b/src/include/optimizer/prep.h
index 0934e63..32b3bf4 100644
--- a/src/include/optimizer/prep.h
+++ b/src/include/optimizer/prep.h
@@ -24,7 +24,7 @@
extern void pull_up_sublinks(PlannerInfo *root);
extern void inline_set_returning_functions(PlannerInfo *root);
extern Node *pull_up_subqueries(PlannerInfo *root, Node *jtnode);
-extern void flatten_simple_union_all(PlannerInfo *root);
+extern void flatten_simple_union(PlannerInfo *root);
extern void reduce_outer_joins(PlannerInfo *root);
extern Relids get_relids_in_jointree(Node *jtnode, bool include_joins);
extern Relids get_relids_for_join(PlannerInfo *root, int joinrelid);
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers