mirror of
https://github.com/postgres/postgres.git
synced 2025-11-07 19:06:32 +03:00
Marginal hack to avoid spending a lot of time in find_join_rel during
large planning problems: when the list of join rels gets too long, make an auxiliary hash table that hashes on the identifying Bitmapset.
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_eval.c,v 1.74 2005/06/05 22:32:55 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_eval.c,v 1.75 2005/06/08 23:02:04 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -47,7 +47,8 @@ geqo_eval(Gene *tour, int num_gene, GeqoEvalData *evaldata)
|
||||
MemoryContext oldcxt;
|
||||
RelOptInfo *joinrel;
|
||||
Cost fitness;
|
||||
List *savelist;
|
||||
int savelength;
|
||||
struct HTAB *savehash;
|
||||
|
||||
/*
|
||||
* Because gimme_tree considers both left- and right-sided trees,
|
||||
@@ -83,13 +84,19 @@ geqo_eval(Gene *tour, int num_gene, GeqoEvalData *evaldata)
|
||||
* gimme_tree will add entries to root->join_rel_list, which may or may
|
||||
* not already contain some entries. The newly added entries will be
|
||||
* recycled by the MemoryContextDelete below, so we must ensure that
|
||||
* the list is restored to its former state before exiting. With the
|
||||
* new List implementation, the easiest way is to make a duplicate list
|
||||
* that gimme_tree can modify.
|
||||
* the list is restored to its former state before exiting. We can
|
||||
* do this by truncating the list to its original length. NOTE this
|
||||
* assumes that any added entries are appended at the end!
|
||||
*
|
||||
* We also must take care not to mess up the outer join_rel_hash,
|
||||
* if there is one. We can do this by just temporarily setting the
|
||||
* link to NULL. (If we are dealing with enough join rels, which we
|
||||
* very likely are, a new hash table will get built and used locally.)
|
||||
*/
|
||||
savelist = evaldata->root->join_rel_list;
|
||||
savelength = list_length(evaldata->root->join_rel_list);
|
||||
savehash = evaldata->root->join_rel_hash;
|
||||
|
||||
evaldata->root->join_rel_list = list_copy(savelist);
|
||||
evaldata->root->join_rel_hash = NULL;
|
||||
|
||||
/* construct the best path for the given combination of relations */
|
||||
joinrel = gimme_tree(tour, num_gene, evaldata);
|
||||
@@ -105,8 +112,13 @@ geqo_eval(Gene *tour, int num_gene, GeqoEvalData *evaldata)
|
||||
else
|
||||
fitness = DBL_MAX;
|
||||
|
||||
/* restore join_rel_list */
|
||||
evaldata->root->join_rel_list = savelist;
|
||||
/*
|
||||
* Restore join_rel_list to its former state, and put back original
|
||||
* hashtable if any.
|
||||
*/
|
||||
evaldata->root->join_rel_list = list_truncate(evaldata->root->join_rel_list,
|
||||
savelength);
|
||||
evaldata->root->join_rel_hash = savehash;
|
||||
|
||||
/* release all the memory acquired within gimme_tree */
|
||||
MemoryContextSwitchTo(oldcxt);
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_main.c,v 1.49 2005/06/05 22:32:55 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_main.c,v 1.50 2005/06/08 23:02:04 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -252,7 +252,6 @@ geqo(PlannerInfo *root, int number_of_rels, List *initial_rels)
|
||||
*/
|
||||
best_tour = (Gene *) pool->data[0].string;
|
||||
|
||||
/* root->join_rel_list will be modified during this ! */
|
||||
best_rel = gimme_tree(best_tour, pool->string_length, &evaldata);
|
||||
|
||||
if (best_rel == NULL)
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/planmain.c,v 1.83 2005/06/06 04:13:35 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/planmain.c,v 1.84 2005/06/08 23:02:04 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -116,6 +116,7 @@ query_planner(PlannerInfo *root, List *tlist, double tuple_fraction,
|
||||
root->base_rel_array = (RelOptInfo **)
|
||||
palloc0(root->base_rel_array_size * sizeof(RelOptInfo *));
|
||||
root->join_rel_list = NIL;
|
||||
root->join_rel_hash = NULL;
|
||||
root->equi_key_list = NIL;
|
||||
|
||||
/*
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/relnode.c,v 1.68 2005/06/06 04:13:36 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/relnode.c,v 1.69 2005/06/08 23:02:05 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -21,8 +21,15 @@
|
||||
#include "optimizer/restrictinfo.h"
|
||||
#include "optimizer/tlist.h"
|
||||
#include "parser/parsetree.h"
|
||||
#include "utils/hsearch.h"
|
||||
|
||||
|
||||
typedef struct JoinHashEntry
|
||||
{
|
||||
Relids join_relids; /* hash key --- MUST BE FIRST */
|
||||
RelOptInfo *join_rel;
|
||||
} JoinHashEntry;
|
||||
|
||||
static RelOptInfo *make_reloptinfo(PlannerInfo *root, int relid,
|
||||
RelOptKind reloptkind);
|
||||
static void build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel,
|
||||
@@ -197,6 +204,47 @@ find_base_rel(PlannerInfo *root, int relid)
|
||||
return NULL; /* keep compiler quiet */
|
||||
}
|
||||
|
||||
/*
|
||||
* build_join_rel_hash
|
||||
* Construct the auxiliary hash table for join relations.
|
||||
*/
|
||||
static void
|
||||
build_join_rel_hash(PlannerInfo *root)
|
||||
{
|
||||
HTAB *hashtab;
|
||||
HASHCTL hash_ctl;
|
||||
ListCell *l;
|
||||
|
||||
/* Create the hash table */
|
||||
MemSet(&hash_ctl, 0, sizeof(hash_ctl));
|
||||
hash_ctl.keysize = sizeof(Relids);
|
||||
hash_ctl.entrysize = sizeof(JoinHashEntry);
|
||||
hash_ctl.hash = bitmap_hash;
|
||||
hash_ctl.match = bitmap_match;
|
||||
hash_ctl.hcxt = CurrentMemoryContext;
|
||||
hashtab = hash_create("JoinRelHashTable",
|
||||
256L,
|
||||
&hash_ctl,
|
||||
HASH_ELEM | HASH_FUNCTION | HASH_COMPARE | HASH_CONTEXT);
|
||||
|
||||
/* Insert all the already-existing joinrels */
|
||||
foreach(l, root->join_rel_list)
|
||||
{
|
||||
RelOptInfo *rel = (RelOptInfo *) lfirst(l);
|
||||
JoinHashEntry *hentry;
|
||||
bool found;
|
||||
|
||||
hentry = (JoinHashEntry *) hash_search(hashtab,
|
||||
&(rel->relids),
|
||||
HASH_ENTER,
|
||||
&found);
|
||||
Assert(!found);
|
||||
hentry->join_rel = rel;
|
||||
}
|
||||
|
||||
root->join_rel_hash = hashtab;
|
||||
}
|
||||
|
||||
/*
|
||||
* find_join_rel
|
||||
* Returns relation entry corresponding to 'relids' (a set of RT indexes),
|
||||
@@ -205,14 +253,44 @@ find_base_rel(PlannerInfo *root, int relid)
|
||||
RelOptInfo *
|
||||
find_join_rel(PlannerInfo *root, Relids relids)
|
||||
{
|
||||
ListCell *l;
|
||||
/*
|
||||
* Switch to using hash lookup when list grows "too long". The threshold
|
||||
* is arbitrary and is known only here.
|
||||
*/
|
||||
if (!root->join_rel_hash && list_length(root->join_rel_list) > 32)
|
||||
build_join_rel_hash(root);
|
||||
|
||||
foreach(l, root->join_rel_list)
|
||||
/*
|
||||
* Use either hashtable lookup or linear search, as appropriate.
|
||||
*
|
||||
* Note: the seemingly redundant hashkey variable is used to avoid
|
||||
* taking the address of relids; unless the compiler is exceedingly
|
||||
* smart, doing so would force relids out of a register and thus
|
||||
* probably slow down the list-search case.
|
||||
*/
|
||||
if (root->join_rel_hash)
|
||||
{
|
||||
RelOptInfo *rel = (RelOptInfo *) lfirst(l);
|
||||
Relids hashkey = relids;
|
||||
JoinHashEntry *hentry;
|
||||
|
||||
if (bms_equal(rel->relids, relids))
|
||||
return rel;
|
||||
hentry = (JoinHashEntry *) hash_search(root->join_rel_hash,
|
||||
&hashkey,
|
||||
HASH_FIND,
|
||||
NULL);
|
||||
if (hentry)
|
||||
return hentry->join_rel;
|
||||
}
|
||||
else
|
||||
{
|
||||
ListCell *l;
|
||||
|
||||
foreach(l, root->join_rel_list)
|
||||
{
|
||||
RelOptInfo *rel = (RelOptInfo *) lfirst(l);
|
||||
|
||||
if (bms_equal(rel->relids, relids))
|
||||
return rel;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -329,9 +407,24 @@ build_join_rel(PlannerInfo *root,
|
||||
jointype, restrictlist);
|
||||
|
||||
/*
|
||||
* Add the joinrel to the query's joinrel list.
|
||||
* Add the joinrel to the query's joinrel list, and store it into
|
||||
* the auxiliary hashtable if there is one. NB: GEQO requires us
|
||||
* to append the new joinrel to the end of the list!
|
||||
*/
|
||||
root->join_rel_list = lcons(joinrel, root->join_rel_list);
|
||||
root->join_rel_list = lappend(root->join_rel_list, joinrel);
|
||||
|
||||
if (root->join_rel_hash)
|
||||
{
|
||||
JoinHashEntry *hentry;
|
||||
bool found;
|
||||
|
||||
hentry = (JoinHashEntry *) hash_search(root->join_rel_hash,
|
||||
&(joinrel->relids),
|
||||
HASH_ENTER,
|
||||
&found);
|
||||
Assert(!found);
|
||||
hentry->join_rel = joinrel;
|
||||
}
|
||||
|
||||
return joinrel;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user