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:
parent
149af068ff
commit
cdf0231c88
@ -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:
|
||||
|
@ -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.
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user