Commit 400e2c93 authored by Tom Lane's avatar Tom Lane

Rewrite GEQO's gimme_tree function so that it always finds a legal join

sequence, even when the input "tour" doesn't lead directly to such a sequence.
The stack logic that was added in 2004 only supported cases where relations
that had to be joined to each other (due to join order restrictions) were
adjacent in the tour.  However, relying on a random search to figure that out
is tremendously inefficient in large join problems, and could even fail
completely (leading to "failed to make a valid plan" errors) if
random_init_pool ran out of patience.  It seems better to make the
tour-to-plan transformation a little bit fuzzier so that every tour can form
a legal plan, even though this means that apparently different tours will
sometimes yield the same plan.

In the same vein, get rid of the logic that knew that tours (a,b,c,d,...)
are the same as tours (b,a,c,d,...), and therefore insisted the latter
are invalid.  The chance of generating two tours that differ only in
this way isn't that high, and throwing out 50% of possible tours to
avoid such duplication seems more likely to waste valuable genetic-
refinement generations than to do anything useful.

This leaves us with no cases in which geqo_eval will deem a tour invalid,
so get rid of assorted kluges that tried to deal with such cases, in
particular the undocumented assumption that DBL_MAX is an impossible
plan cost.

This is all per testing of Robert Haas' lets-remove-the-collapse-limits
patch.  That idea has crashed and burned, at least for now, but we still
got something useful out of it.

It's possible we should back-patch this change, since the "failed to make a
valid plan" error can happen in existing releases; but I'd rather not until
it has gotten more testing.
parent a43b190e
This diff is collapsed.
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_main.c,v 1.57 2009/07/16 20:55:44 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_main.c,v 1.58 2009/07/19 21:00:43 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -257,9 +257,6 @@ geqo(PlannerInfo *root, int number_of_rels, List *initial_rels) ...@@ -257,9 +257,6 @@ geqo(PlannerInfo *root, int number_of_rels, List *initial_rels)
best_rel = gimme_tree(root, best_tour, pool->string_length); best_rel = gimme_tree(root, best_tour, pool->string_length);
if (best_rel == NULL)
elog(ERROR, "failed to make a valid plan");
/* DBG: show the query plan */ /* DBG: show the query plan */
#ifdef NOT_USED #ifdef NOT_USED
print_plan(best_plan, root); print_plan(best_plan, root);
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_pool.c,v 1.34 2009/07/16 20:55:44 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_pool.c,v 1.35 2009/07/19 21:00:43 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -92,37 +92,13 @@ random_init_pool(PlannerInfo *root, Pool *pool) ...@@ -92,37 +92,13 @@ random_init_pool(PlannerInfo *root, Pool *pool)
{ {
Chromosome *chromo = (Chromosome *) pool->data; Chromosome *chromo = (Chromosome *) pool->data;
int i; int i;
int bad = 0;
/* for (i = 0; i < pool->size; i++)
* We immediately discard any invalid individuals (those that geqo_eval
* returns DBL_MAX for), thereby not wasting pool space on them.
*
* If we fail to make any valid individuals after 10000 tries, give up;
* this probably means something is broken, and we shouldn't just let
* ourselves get stuck in an infinite loop.
*/
i = 0;
while (i < pool->size)
{ {
init_tour(root, chromo[i].string, pool->string_length); init_tour(root, chromo[i].string, pool->string_length);
pool->data[i].worth = geqo_eval(root, chromo[i].string, pool->data[i].worth = geqo_eval(root, chromo[i].string,
pool->string_length); pool->string_length);
if (pool->data[i].worth < DBL_MAX)
i++;
else
{
bad++;
if (i == 0 && bad >= 10000)
elog(ERROR, "failed to make a valid plan");
}
} }
#ifdef GEQO_DEBUG
if (bad > 0)
elog(DEBUG1, "%d invalid tours found while selecting %d pool entries",
bad, pool->size);
#endif
} }
/* /*
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* geqo_recombination.c * geqo_recombination.c
* misc recombination procedures * misc recombination procedures
* *
* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_recombination.c,v 1.16 2009/07/16 20:55:44 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_recombination.c,v 1.17 2009/07/19 21:00:43 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -61,18 +61,6 @@ init_tour(PlannerInfo *root, Gene *tour, int num_gene) ...@@ -61,18 +61,6 @@ init_tour(PlannerInfo *root, Gene *tour, int num_gene)
remainder--; remainder--;
} }
/*
* Since geqo_eval() will reject tours where tour[0] > tour[1], we may as
* well switch the two to make it a valid tour.
*/
if (num_gene >= 2 && tour[0] > tour[1])
{
Gene gtmp = tour[0];
tour[0] = tour[1];
tour[1] = gtmp;
}
pfree(tmp); pfree(tmp);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment