1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-21 16:02:15 +03:00

Use fuzzy path cost tiebreaking rule in our oldest supported branches.

We've been doing it that way since 9.2, cf commit 33e99153e9,
but some recently-added regression test cases are making a few buildfarm
members fail (ie choose the "wrong" plan) in 9.0 and 9.1 due to
platform-specific roundoff differences in cost calculations.  To fix,
back-port the patch that made add_path treat cost difference ratios of
less than 1e-10 as equal.
This commit is contained in:
Tom Lane
2015-08-15 11:02:17 -04:00
parent 24906bbc22
commit 9d6af7367e

View File

@ -92,44 +92,45 @@ compare_path_costs(Path *path1, Path *path2, CostSelector criterion)
* same if they agree to within a "fuzz factor". This is used by add_path * same if they agree to within a "fuzz factor". This is used by add_path
* to avoid keeping both of a pair of paths that really have insignificantly * to avoid keeping both of a pair of paths that really have insignificantly
* different cost. * different cost.
*
* The fuzz_factor argument must be 1.0 plus delta, where delta is the
* fraction of the smaller cost that is considered to be a significant
* difference. For example, fuzz_factor = 1.01 makes the fuzziness limit
* be 1% of the smaller cost.
*/ */
static int static int
compare_fuzzy_path_costs(Path *path1, Path *path2, CostSelector criterion) compare_fuzzy_path_costs(Path *path1, Path *path2, CostSelector criterion,
double fuzz_factor)
{ {
/*
* We use a fuzz factor of 1% of the smaller cost.
*
* XXX does this percentage need to be user-configurable?
*/
if (criterion == STARTUP_COST) if (criterion == STARTUP_COST)
{ {
if (path1->startup_cost > path2->startup_cost * 1.01) if (path1->startup_cost > path2->startup_cost * fuzz_factor)
return +1; return +1;
if (path2->startup_cost > path1->startup_cost * 1.01) if (path2->startup_cost > path1->startup_cost * fuzz_factor)
return -1; return -1;
/* /*
* If paths have the same startup cost (not at all unlikely), order * If paths have the same startup cost (not at all unlikely), order
* them by total cost. * them by total cost.
*/ */
if (path1->total_cost > path2->total_cost * 1.01) if (path1->total_cost > path2->total_cost * fuzz_factor)
return +1; return +1;
if (path2->total_cost > path1->total_cost * 1.01) if (path2->total_cost > path1->total_cost * fuzz_factor)
return -1; return -1;
} }
else else
{ {
if (path1->total_cost > path2->total_cost * 1.01) if (path1->total_cost > path2->total_cost * fuzz_factor)
return +1; return +1;
if (path2->total_cost > path1->total_cost * 1.01) if (path2->total_cost > path1->total_cost * fuzz_factor)
return -1; return -1;
/* /*
* If paths have the same total cost, order them by startup cost. * If paths have the same total cost, order them by startup cost.
*/ */
if (path1->startup_cost > path2->startup_cost * 1.01) if (path1->startup_cost > path2->startup_cost * fuzz_factor)
return +1; return +1;
if (path2->startup_cost > path1->startup_cost * 1.01) if (path2->startup_cost > path1->startup_cost * fuzz_factor)
return -1; return -1;
} }
return 0; return 0;
@ -277,9 +278,11 @@ add_path(RelOptInfo *parent_rel, Path *new_path)
/* /*
* As of Postgres 8.0, we use fuzzy cost comparison to avoid wasting * As of Postgres 8.0, we use fuzzy cost comparison to avoid wasting
* cycles keeping paths that are really not significantly different in * cycles keeping paths that are really not significantly different in
* cost. * cost. We use a 1% fuzziness limit. (XXX does this percentage need
* to be user-configurable?)
*/ */
costcmp = compare_fuzzy_path_costs(new_path, old_path, TOTAL_COST); costcmp = compare_fuzzy_path_costs(new_path, old_path,
TOTAL_COST, 1.01);
/* /*
* If the two paths compare differently for startup and total cost, * If the two paths compare differently for startup and total cost,
@ -292,7 +295,7 @@ add_path(RelOptInfo *parent_rel, Path *new_path)
*/ */
if (costcmp == 0 || if (costcmp == 0 ||
costcmp == compare_fuzzy_path_costs(new_path, old_path, costcmp == compare_fuzzy_path_costs(new_path, old_path,
STARTUP_COST)) STARTUP_COST, 1.01))
{ {
switch (compare_pathkeys(new_path->pathkeys, old_path->pathkeys)) switch (compare_pathkeys(new_path->pathkeys, old_path->pathkeys))
{ {
@ -305,11 +308,16 @@ add_path(RelOptInfo *parent_rel, Path *new_path)
{ {
/* /*
* Same pathkeys, and fuzzily the same cost, so keep * Same pathkeys, and fuzzily the same cost, so keep
* just one --- but we'll do an exact cost comparison * just one; to decide which, do a fuzzy total-cost
* to decide which. * comparison with very small fuzz limit. (We used to
* do an exact cost comparison, but that results in
* annoying platform-specific plan variations due to
* roundoff in the cost estimates.) If things are
* still tied, arbitrarily keep only the old path.
*/ */
if (compare_path_costs(new_path, old_path, if (compare_fuzzy_path_costs(new_path, old_path,
TOTAL_COST) < 0) TOTAL_COST,
1.0000000001) < 0)
remove_old = true; /* new dominates old */ remove_old = true; /* new dominates old */
else else
accept_new = false; /* old equals or dominates new */ accept_new = false; /* old equals or dominates new */