mirror of
https://github.com/postgres/postgres.git
synced 2025-07-15 19:21:59 +03:00
Refactor planner's pathkeys data structure to create a separate, explicit
representation of equivalence classes of variables. This is an extensive rewrite, but it brings a number of benefits: * planner no longer fails in the presence of "incomplete" operator families that don't offer operators for every possible combination of datatypes. * avoid generating and then discarding redundant equality clauses. * remove bogus assumption that derived equalities always use operators named "=". * mergejoins can work with a variety of sort orders (e.g., descending) now, instead of tying each mergejoinable operator to exactly one sort order. * better recognition of redundant sort columns. * can make use of equalities appearing underneath an outer join.
This commit is contained in:
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/relnode.c,v 1.84 2007/01/05 22:19:33 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/relnode.c,v 1.85 2007/01/20 20:45:40 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -16,6 +16,7 @@
|
||||
|
||||
#include "optimizer/cost.h"
|
||||
#include "optimizer/pathnode.h"
|
||||
#include "optimizer/paths.h"
|
||||
#include "optimizer/plancat.h"
|
||||
#include "optimizer/restrictinfo.h"
|
||||
#include "parser/parsetree.h"
|
||||
@ -31,17 +32,18 @@ typedef struct JoinHashEntry
|
||||
static void build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel,
|
||||
RelOptInfo *input_rel);
|
||||
static List *build_joinrel_restrictlist(PlannerInfo *root,
|
||||
RelOptInfo *joinrel,
|
||||
RelOptInfo *outer_rel,
|
||||
RelOptInfo *inner_rel,
|
||||
JoinType jointype);
|
||||
RelOptInfo *joinrel,
|
||||
RelOptInfo *outer_rel,
|
||||
RelOptInfo *inner_rel);
|
||||
static void build_joinrel_joinlist(RelOptInfo *joinrel,
|
||||
RelOptInfo *outer_rel,
|
||||
RelOptInfo *inner_rel);
|
||||
static List *subbuild_joinrel_restrictlist(RelOptInfo *joinrel,
|
||||
List *joininfo_list);
|
||||
static void subbuild_joinrel_joinlist(RelOptInfo *joinrel,
|
||||
List *joininfo_list);
|
||||
List *joininfo_list,
|
||||
List *new_restrictlist);
|
||||
static List *subbuild_joinrel_joinlist(RelOptInfo *joinrel,
|
||||
List *joininfo_list,
|
||||
List *new_joininfo);
|
||||
|
||||
|
||||
/*
|
||||
@ -84,6 +86,7 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind)
|
||||
rel->baserestrictcost.startup = 0;
|
||||
rel->baserestrictcost.per_tuple = 0;
|
||||
rel->joininfo = NIL;
|
||||
rel->has_eclass_joins = false;
|
||||
rel->index_outer_relids = NULL;
|
||||
rel->index_inner_paths = NIL;
|
||||
|
||||
@ -303,8 +306,7 @@ build_join_rel(PlannerInfo *root,
|
||||
*restrictlist_ptr = build_joinrel_restrictlist(root,
|
||||
joinrel,
|
||||
outer_rel,
|
||||
inner_rel,
|
||||
jointype);
|
||||
inner_rel);
|
||||
return joinrel;
|
||||
}
|
||||
|
||||
@ -335,6 +337,7 @@ build_join_rel(PlannerInfo *root,
|
||||
joinrel->baserestrictcost.startup = 0;
|
||||
joinrel->baserestrictcost.per_tuple = 0;
|
||||
joinrel->joininfo = NIL;
|
||||
joinrel->has_eclass_joins = false;
|
||||
joinrel->index_outer_relids = NULL;
|
||||
joinrel->index_inner_paths = NIL;
|
||||
|
||||
@ -354,15 +357,18 @@ build_join_rel(PlannerInfo *root,
|
||||
* caller might or might not need the restrictlist, but I need it anyway
|
||||
* for set_joinrel_size_estimates().)
|
||||
*/
|
||||
restrictlist = build_joinrel_restrictlist(root,
|
||||
joinrel,
|
||||
outer_rel,
|
||||
inner_rel,
|
||||
jointype);
|
||||
restrictlist = build_joinrel_restrictlist(root, joinrel,
|
||||
outer_rel, inner_rel);
|
||||
if (restrictlist_ptr)
|
||||
*restrictlist_ptr = restrictlist;
|
||||
build_joinrel_joinlist(joinrel, outer_rel, inner_rel);
|
||||
|
||||
/*
|
||||
* This is also the right place to check whether the joinrel has any
|
||||
* pending EquivalenceClass joins.
|
||||
*/
|
||||
joinrel->has_eclass_joins = has_relevant_eclass_joinclause(root, joinrel);
|
||||
|
||||
/*
|
||||
* Set estimates of the joinrel's size.
|
||||
*/
|
||||
@ -468,15 +474,15 @@ build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel,
|
||||
* 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.
|
||||
* In many case we will find the same RestrictInfos in both input
|
||||
* relations' joinlists, so be careful to eliminate duplicates.
|
||||
* Pointer equality should be a sufficient test for dups, since all
|
||||
* the various joinlist entries ultimately refer to RestrictInfos
|
||||
* pushed into them by distribute_restrictinfo_to_rels().
|
||||
*
|
||||
* 'joinrel' is a join relation node
|
||||
* 'outer_rel' and 'inner_rel' are a pair of relations that can be joined
|
||||
* to form joinrel.
|
||||
* 'jointype' is the type of join used.
|
||||
*
|
||||
* build_joinrel_restrictlist() returns a list of relevant restrictinfos,
|
||||
* whereas build_joinrel_joinlist() stores its results in the joinrel's
|
||||
@ -491,33 +497,27 @@ static List *
|
||||
build_joinrel_restrictlist(PlannerInfo *root,
|
||||
RelOptInfo *joinrel,
|
||||
RelOptInfo *outer_rel,
|
||||
RelOptInfo *inner_rel,
|
||||
JoinType jointype)
|
||||
RelOptInfo *inner_rel)
|
||||
{
|
||||
List *result;
|
||||
List *rlist;
|
||||
|
||||
/*
|
||||
* Collect all the clauses that syntactically belong at this level.
|
||||
* Collect all the clauses that syntactically belong at this level,
|
||||
* eliminating any duplicates (important since we will see many of the
|
||||
* same clauses arriving from both input relations).
|
||||
*/
|
||||
rlist = list_concat(subbuild_joinrel_restrictlist(joinrel,
|
||||
outer_rel->joininfo),
|
||||
subbuild_joinrel_restrictlist(joinrel,
|
||||
inner_rel->joininfo));
|
||||
|
||||
result = subbuild_joinrel_restrictlist(joinrel, outer_rel->joininfo, NIL);
|
||||
result = subbuild_joinrel_restrictlist(joinrel, inner_rel->joininfo, result);
|
||||
/*
|
||||
* 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.
|
||||
* Add on any clauses derived from EquivalenceClasses. These cannot be
|
||||
* redundant with the clauses in the joininfo lists, so don't bother
|
||||
* checking.
|
||||
*/
|
||||
result = remove_redundant_join_clauses(root, rlist,
|
||||
IS_OUTER_JOIN(jointype));
|
||||
|
||||
list_free(rlist);
|
||||
result = list_concat(result,
|
||||
generate_join_implied_equalities(root,
|
||||
joinrel,
|
||||
outer_rel,
|
||||
inner_rel));
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -527,15 +527,24 @@ build_joinrel_joinlist(RelOptInfo *joinrel,
|
||||
RelOptInfo *outer_rel,
|
||||
RelOptInfo *inner_rel)
|
||||
{
|
||||
subbuild_joinrel_joinlist(joinrel, outer_rel->joininfo);
|
||||
subbuild_joinrel_joinlist(joinrel, inner_rel->joininfo);
|
||||
List *result;
|
||||
|
||||
/*
|
||||
* Collect all the clauses that syntactically belong above this level,
|
||||
* eliminating any duplicates (important since we will see many of the
|
||||
* same clauses arriving from both input relations).
|
||||
*/
|
||||
result = subbuild_joinrel_joinlist(joinrel, outer_rel->joininfo, NIL);
|
||||
result = subbuild_joinrel_joinlist(joinrel, inner_rel->joininfo, result);
|
||||
|
||||
joinrel->joininfo = result;
|
||||
}
|
||||
|
||||
static List *
|
||||
subbuild_joinrel_restrictlist(RelOptInfo *joinrel,
|
||||
List *joininfo_list)
|
||||
List *joininfo_list,
|
||||
List *new_restrictlist)
|
||||
{
|
||||
List *restrictlist = NIL;
|
||||
ListCell *l;
|
||||
|
||||
foreach(l, joininfo_list)
|
||||
@ -546,10 +555,12 @@ subbuild_joinrel_restrictlist(RelOptInfo *joinrel,
|
||||
{
|
||||
/*
|
||||
* This clause becomes a restriction clause for the joinrel, since
|
||||
* it refers to no outside rels. We don't bother to check for
|
||||
* duplicates here --- build_joinrel_restrictlist will do that.
|
||||
* it refers to no outside rels. Add it to the list, being
|
||||
* careful to eliminate duplicates. (Since RestrictInfo nodes in
|
||||
* different joinlists will have been multiply-linked rather than
|
||||
* copied, pointer equality should be a sufficient test.)
|
||||
*/
|
||||
restrictlist = lappend(restrictlist, rinfo);
|
||||
new_restrictlist = list_append_unique_ptr(new_restrictlist, rinfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -560,12 +571,13 @@ subbuild_joinrel_restrictlist(RelOptInfo *joinrel,
|
||||
}
|
||||
}
|
||||
|
||||
return restrictlist;
|
||||
return new_restrictlist;
|
||||
}
|
||||
|
||||
static void
|
||||
static List *
|
||||
subbuild_joinrel_joinlist(RelOptInfo *joinrel,
|
||||
List *joininfo_list)
|
||||
List *joininfo_list,
|
||||
List *new_joininfo)
|
||||
{
|
||||
ListCell *l;
|
||||
|
||||
@ -585,15 +597,14 @@ subbuild_joinrel_joinlist(RelOptInfo *joinrel,
|
||||
{
|
||||
/*
|
||||
* This clause is still a join clause at this level, so add it to
|
||||
* the joininfo list for the joinrel, being careful to eliminate
|
||||
* duplicates. (Since RestrictInfo nodes are normally
|
||||
* multiply-linked rather than copied, pointer equality should be
|
||||
* a sufficient test. If two equal() nodes should happen to sneak
|
||||
* in, no great harm is done --- they'll be detected by
|
||||
* redundant-clause testing when they reach a restriction list.)
|
||||
* the new joininfo list, being careful to eliminate
|
||||
* duplicates. (Since RestrictInfo nodes in different joinlists
|
||||
* will have been multiply-linked rather than copied, pointer
|
||||
* equality should be a sufficient test.)
|
||||
*/
|
||||
joinrel->joininfo = list_append_unique_ptr(joinrel->joininfo,
|
||||
rinfo);
|
||||
new_joininfo = list_append_unique_ptr(new_joininfo, rinfo);
|
||||
}
|
||||
}
|
||||
|
||||
return new_joininfo;
|
||||
}
|
||||
|
Reference in New Issue
Block a user