aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/util/relnode.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/util/relnode.c')
-rw-r--r--src/backend/optimizer/util/relnode.c102
1 files changed, 85 insertions, 17 deletions
diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c
index 86d923116a4..3b85f321dfb 100644
--- a/src/backend/optimizer/util/relnode.c
+++ b/src/backend/optimizer/util/relnode.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/util/relnode.c,v 1.33 2001/05/20 20:28:19 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/relnode.c,v 1.34 2001/10/18 16:11:42 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -17,6 +17,7 @@
#include "optimizer/cost.h"
#include "optimizer/joininfo.h"
#include "optimizer/pathnode.h"
+#include "optimizer/paths.h"
#include "optimizer/plancat.h"
#include "optimizer/tlist.h"
#include "parser/parsetree.h"
@@ -24,9 +25,10 @@
static RelOptInfo *make_base_rel(Query *root, int relid);
static List *new_join_tlist(List *tlist, int first_resdomno);
-static List *build_joinrel_restrictlist(RelOptInfo *joinrel,
- RelOptInfo *outer_rel,
- RelOptInfo *inner_rel);
+static List *build_joinrel_restrictlist(Query *root,
+ RelOptInfo *joinrel,
+ RelOptInfo *outer_rel,
+ RelOptInfo *inner_rel);
static void build_joinrel_joinlist(RelOptInfo *joinrel,
RelOptInfo *outer_rel,
RelOptInfo *inner_rel);
@@ -274,7 +276,8 @@ build_join_rel(Query *root,
* particular pair of component relations.
*/
if (restrictlist_ptr)
- *restrictlist_ptr = build_joinrel_restrictlist(joinrel,
+ *restrictlist_ptr = build_joinrel_restrictlist(root,
+ joinrel,
outer_rel,
inner_rel);
return joinrel;
@@ -326,7 +329,10 @@ build_join_rel(Query *root,
* caller might or might not need the restrictlist, but I need it
* anyway for set_joinrel_size_estimates().)
*/
- restrictlist = build_joinrel_restrictlist(joinrel, outer_rel, inner_rel);
+ restrictlist = build_joinrel_restrictlist(root,
+ joinrel,
+ outer_rel,
+ inner_rel);
if (restrictlist_ptr)
*restrictlist_ptr = restrictlist;
build_joinrel_joinlist(joinrel, outer_rel, inner_rel);
@@ -407,6 +413,11 @@ new_join_tlist(List *tlist,
* join paths made from this pair of sub-relations. (It will not need to
* be considered further up the join tree.)
*
+ * When building a restriction list, we eliminate redundant clauses.
+ * We don't try to do that for join clause lists, since the join clauses
+ * aren't really doing anything, just waiting to become part of higher
+ * levels' restriction lists.
+ *
* 'joinrel' is a join relation node
* 'outer_rel' and 'inner_rel' are a pair of relations that can be joined
* to form joinrel.
@@ -421,19 +432,80 @@ new_join_tlist(List *tlist,
* the original nodes in the lists made for the join relation.
*/
static List *
-build_joinrel_restrictlist(RelOptInfo *joinrel,
+build_joinrel_restrictlist(Query *root,
+ RelOptInfo *joinrel,
RelOptInfo *outer_rel,
RelOptInfo *inner_rel)
{
+ List *result = NIL;
+ List *rlist;
+ List *item;
+
+ /*
+ * Collect all the clauses that syntactically belong at this level.
+ */
+ rlist = nconc(subbuild_joinrel_restrictlist(joinrel,
+ outer_rel->joininfo),
+ subbuild_joinrel_restrictlist(joinrel,
+ inner_rel->joininfo));
/*
- * We must eliminate duplicates, since we will see the same clauses
- * arriving from both input relations...
+ * Eliminate duplicate and redundant clauses.
+ *
+ * We must eliminate duplicates, since we will see many of the same
+ * clauses arriving from both input relations. Also, if a clause is
+ * a mergejoinable clause, it's possible that it is redundant with
+ * previous clauses (see optimizer/README for discussion). We detect
+ * that case and omit the redundant clause from the result list.
+ *
+ * We can detect redundant mergejoinable clauses very cheaply by using
+ * their left and right pathkeys, which uniquely identify the sets of
+ * equijoined variables in question. All the members of a pathkey set
+ * that are in the left relation have already been forced to be equal;
+ * likewise for those in the right relation. So, we need to have only
+ * one clause that checks equality between any set member on the left and
+ * any member on the right; by transitivity, all the rest are then equal.
*/
- return set_union(subbuild_joinrel_restrictlist(joinrel,
- outer_rel->joininfo),
- subbuild_joinrel_restrictlist(joinrel,
- inner_rel->joininfo));
+ foreach(item, rlist)
+ {
+ RestrictInfo *rinfo = (RestrictInfo *) lfirst(item);
+
+ /* eliminate duplicates */
+ if (member(rinfo, result))
+ continue;
+
+ /* check for redundant merge clauses */
+ if (rinfo->mergejoinoperator != InvalidOid)
+ {
+ bool redundant = false;
+ List *olditem;
+
+ cache_mergeclause_pathkeys(root, rinfo);
+
+ foreach(olditem, result)
+ {
+ RestrictInfo *oldrinfo = (RestrictInfo *) lfirst(olditem);
+
+ if (oldrinfo->mergejoinoperator != InvalidOid &&
+ rinfo->left_pathkey == oldrinfo->left_pathkey &&
+ rinfo->right_pathkey == oldrinfo->right_pathkey)
+ {
+ redundant = true;
+ break;
+ }
+ }
+
+ if (redundant)
+ continue;
+ }
+
+ /* otherwise, add it to result list */
+ result = lappend(result, rinfo);
+ }
+
+ freeList(rlist);
+
+ return result;
}
static void
@@ -458,7 +530,6 @@ subbuild_joinrel_restrictlist(RelOptInfo *joinrel,
if (is_subseti(joininfo->unjoined_relids, joinrel->relids))
{
-
/*
* Clauses in this JoinInfo list become restriction clauses
* for the joinrel, since they refer to no outside rels.
@@ -471,7 +542,6 @@ subbuild_joinrel_restrictlist(RelOptInfo *joinrel,
}
else
{
-
/*
* These clauses are still join clauses at this level, so we
* ignore them in this routine.
@@ -497,7 +567,6 @@ subbuild_joinrel_joinlist(RelOptInfo *joinrel,
joinrel->relids);
if (new_unjoined_relids == NIL)
{
-
/*
* Clauses in this JoinInfo list become restriction clauses
* for the joinrel, since they refer to no outside rels. So we
@@ -506,7 +575,6 @@ subbuild_joinrel_joinlist(RelOptInfo *joinrel,
}
else
{
-
/*
* These clauses are still join clauses at this level, so find
* or make the appropriate JoinInfo item for the joinrel, and