Create a function variable "join_search_hook" to let plugins override the

join search order portion of the planner; this is specifically intended to
simplify developing a replacement for GEQO planning.  Patch by Julius
Stroffek, editorialized on by me.  I renamed make_one_rel_by_joins to
standard_join_search and make_rels_by_joins to join_search_one_level to better
reflect their place within this scheme.
This commit is contained in:
Tom Lane 2007-09-26 18:51:51 +00:00
parent 149af068ff
commit cdf0231c88
4 changed files with 55 additions and 26 deletions

View File

@ -292,16 +292,17 @@ planner()
find qual clauses that enable merge and hash joins
----make_one_rel()
set_base_rel_pathlist()
find scan and all index paths for each base relation
find seqscan and all index paths for each base relation
find selectivity of columns used in joins
-----make_one_rel_by_joins()
jump to geqo if needed
else call make_rels_by_joins() for each level of join tree needed
make_rels_by_joins():
make_rel_from_joinlist()
hand off join subproblems to a plugin, GEQO, or standard_join_search()
-----standard_join_search()
call join_search_one_level() for each level of join tree needed
join_search_one_level():
For each joinrel of the prior level, do make_rels_by_clause_joins()
if it has join clauses, or make_rels_by_clauseless_joins() if not.
Also generate "bushy plan" joins between joinrels of lower levels.
Back at make_one_rel_by_joins(), apply set_cheapest() to extract the
Back at standard_join_search(), apply set_cheapest() to extract the
cheapest path for each newly constructed joinrel.
Loop back if this wasn't the top join level.
Back at query_planner:

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.164 2007/05/26 18:23:01 tgl Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.165 2007/09/26 18:51:50 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -37,6 +37,9 @@
bool enable_geqo = false; /* just in case GUC doesn't set it */
int geqo_threshold;
/* Hook for plugins to replace standard_join_search() */
join_search_hook_type join_search_hook = NULL;
static void set_base_rel_pathlists(PlannerInfo *root);
static void set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
@ -53,8 +56,6 @@ static void set_function_pathlist(PlannerInfo *root, RelOptInfo *rel,
static void set_values_pathlist(PlannerInfo *root, RelOptInfo *rel,
RangeTblEntry *rte);
static RelOptInfo *make_rel_from_joinlist(PlannerInfo *root, List *joinlist);
static RelOptInfo *make_one_rel_by_joins(PlannerInfo *root, int levels_needed,
List *initial_rels);
static bool subquery_is_pushdown_safe(Query *subquery, Query *topquery,
bool *differentTypes);
static bool recurse_pushdown_safe(Node *setOp, Query *topquery,
@ -672,18 +673,20 @@ make_rel_from_joinlist(PlannerInfo *root, List *joinlist)
{
/*
* Consider the different orders in which we could join the rels,
* using either GEQO or regular optimizer.
* using a plugin, GEQO, or the regular join search code.
*/
if (enable_geqo && levels_needed >= geqo_threshold)
if (join_search_hook)
return (*join_search_hook) (root, levels_needed, initial_rels);
else if (enable_geqo && levels_needed >= geqo_threshold)
return geqo(root, levels_needed, initial_rels);
else
return make_one_rel_by_joins(root, levels_needed, initial_rels);
return standard_join_search(root, levels_needed, initial_rels);
}
}
/*
* make_one_rel_by_joins
* Find all possible joinpaths for a query by successively finding ways
* standard_join_search
* Find possible joinpaths for a query by successively finding ways
* to join component relations into join relations.
*
* 'levels_needed' is the number of iterations needed, ie, the number of
@ -691,12 +694,27 @@ make_rel_from_joinlist(PlannerInfo *root, List *joinlist)
*
* 'initial_rels' is a list of RelOptInfo nodes for each independent
* jointree item. These are the components to be joined together.
* Note that levels_needed == list_length(initial_rels).
*
* Returns the final level of join relations, i.e., the relation that is
* the result of joining all the original relations together.
* At least one implementation path must be provided for this relation and
* all required sub-relations.
*
* To support loadable plugins that modify planner behavior by changing the
* join searching algorithm, we provide a hook variable that lets a plugin
* replace or supplement this function. Any such hook must return the same
* final join relation as the standard code would, but it might have a
* different set of implementation paths attached, and only the sub-joinrels
* needed for these paths need have been instantiated.
*
* Note to plugin authors: the functions invoked during standard_join_search()
* modify root->join_rel_list and root->join_rel_hash. If you want to do more
* than one join-order search, you'll probably need to save and restore the
* original states of those data structures. See geqo_eval() for an example.
*/
static RelOptInfo *
make_one_rel_by_joins(PlannerInfo *root, int levels_needed, List *initial_rels)
RelOptInfo *
standard_join_search(PlannerInfo *root, int levels_needed, List *initial_rels)
{
List **joinitems;
int lev;
@ -725,7 +743,7 @@ make_one_rel_by_joins(PlannerInfo *root, int levels_needed, List *initial_rels)
* level, and build paths for making each one from every available
* pair of lower-level relations.
*/
joinitems[lev] = make_rels_by_joins(root, lev, joinitems);
joinitems[lev] = join_search_one_level(root, lev, joinitems);
/*
* Do cleanup work on each just-processed rel.

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/path/joinrels.c,v 1.86 2007/02/16 00:14:01 tgl Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/path/joinrels.c,v 1.87 2007/09/26 18:51:50 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -29,10 +29,10 @@ static bool has_join_restriction(PlannerInfo *root, RelOptInfo *rel);
/*
* make_rels_by_joins
* join_search_one_level
* Consider ways to produce join relations containing exactly 'level'
* jointree items. (This is one step of the dynamic-programming method
* embodied in make_one_rel_by_joins.) Join rel nodes for each feasible
* embodied in standard_join_search.) Join rel nodes for each feasible
* combination of lower-level rels are created and returned in a list.
* Implementation paths are created for each such joinrel, too.
*
@ -40,7 +40,7 @@ static bool has_join_restriction(PlannerInfo *root, RelOptInfo *rel);
* joinrels[j], 1 <= j < level, is a list of rels containing j items.
*/
List *
make_rels_by_joins(PlannerInfo *root, int level, List **joinrels)
join_search_one_level(PlannerInfo *root, int level, List **joinrels)
{
List *result_rels = NIL;
List *new_rels;
@ -638,9 +638,9 @@ make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2)
* Note: this is only a problem if one side of a degenerate outer join
* contains multiple rels, or a clauseless join is required within an IN's
* RHS; else we will find a join path via the "last ditch" case in
* make_rels_by_joins(). We could dispense with this test if we were willing
* to try bushy plans in the "last ditch" case, but that seems much less
* efficient.
* join_search_one_level(). We could dispense with this test if we were
* willing to try bushy plans in the "last ditch" case, but that seems much
* less efficient.
*/
bool
have_join_order_restriction(PlannerInfo *root,

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/optimizer/paths.h,v 1.98 2007/05/22 01:40:33 tgl Exp $
* $PostgreSQL: pgsql/src/include/optimizer/paths.h,v 1.99 2007/09/26 18:51:51 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -23,7 +23,16 @@
extern bool enable_geqo;
extern int geqo_threshold;
/* Hook for plugins to replace standard_join_search() */
typedef RelOptInfo * (*join_search_hook_type) (PlannerInfo *root,
int levels_needed,
List *initial_rels);
extern PGDLLIMPORT join_search_hook_type join_search_hook;
extern RelOptInfo *make_one_rel(PlannerInfo *root, List *joinlist);
extern RelOptInfo *standard_join_search(PlannerInfo *root, int levels_needed,
List *initial_rels);
#ifdef OPTIMIZER_DEBUG
extern void debug_print_rel(PlannerInfo *root, RelOptInfo *rel);
@ -89,7 +98,8 @@ extern void add_paths_to_joinrel(PlannerInfo *root, RelOptInfo *joinrel,
* joinrels.c
* routines to determine which relations to join
*/
extern List *make_rels_by_joins(PlannerInfo *root, int level, List **joinrels);
extern List *join_search_one_level(PlannerInfo *root, int level,
List **joinrels);
extern RelOptInfo *make_join_rel(PlannerInfo *root,
RelOptInfo *rel1, RelOptInfo *rel2);
extern bool have_join_order_restriction(PlannerInfo *root,