aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2015-08-15 11:02:17 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2015-08-15 11:02:33 -0400
commit3218f8c33612baca0a1f44d4a243c598ddebad9d (patch)
treeaf3dd0d11d49545d01c598b53bbb5e6da08caae6
parent8749aafde2179de243bc8ffeec23a28a94ec5def (diff)
downloadpostgresql-3218f8c33612baca0a1f44d4a243c598ddebad9d.tar.gz
postgresql-3218f8c33612baca0a1f44d4a243c598ddebad9d.zip
Use fuzzy path cost tiebreaking rule in our oldest supported branches.
We've been doing it that way since 9.2, cf commit 33e99153e93b9acc, 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.
-rw-r--r--src/backend/optimizer/util/pathnode.c50
1 files changed, 29 insertions, 21 deletions
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index 53f085a1fbc..ec7c091e60c 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -93,44 +93,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
* to avoid keeping both of a pair of paths that really have insignificantly
* 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
-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 (path1->startup_cost > path2->startup_cost * 1.01)
+ if (path1->startup_cost > path2->startup_cost * fuzz_factor)
return +1;
- if (path2->startup_cost > path1->startup_cost * 1.01)
+ if (path2->startup_cost > path1->startup_cost * fuzz_factor)
return -1;
/*
* If paths have the same startup cost (not at all unlikely), order
* them by total cost.
*/
- if (path1->total_cost > path2->total_cost * 1.01)
+ if (path1->total_cost > path2->total_cost * fuzz_factor)
return +1;
- if (path2->total_cost > path1->total_cost * 1.01)
+ if (path2->total_cost > path1->total_cost * fuzz_factor)
return -1;
}
else
{
- if (path1->total_cost > path2->total_cost * 1.01)
+ if (path1->total_cost > path2->total_cost * fuzz_factor)
return +1;
- if (path2->total_cost > path1->total_cost * 1.01)
+ if (path2->total_cost > path1->total_cost * fuzz_factor)
return -1;
/*
* 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;
- if (path2->startup_cost > path1->startup_cost * 1.01)
+ if (path2->startup_cost > path1->startup_cost * fuzz_factor)
return -1;
}
return 0;
@@ -284,9 +285,11 @@ add_path(RelOptInfo *parent_rel, Path *new_path)
/*
* As of Postgres 8.0, we use fuzzy cost comparison to avoid wasting
* 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,
@@ -299,7 +302,7 @@ add_path(RelOptInfo *parent_rel, Path *new_path)
*/
if (costcmp == 0 ||
costcmp == compare_fuzzy_path_costs(new_path, old_path,
- STARTUP_COST))
+ STARTUP_COST, 1.01))
{
switch (compare_pathkeys(new_path->pathkeys, old_path->pathkeys))
{
@@ -312,11 +315,16 @@ add_path(RelOptInfo *parent_rel, Path *new_path)
{
/*
* Same pathkeys, and fuzzily the same cost, so keep
- * just one --- but we'll do an exact cost comparison
- * to decide which.
+ * just one; to decide which, do a fuzzy total-cost
+ * 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,
- TOTAL_COST) < 0)
+ if (compare_fuzzy_path_costs(new_path, old_path,
+ TOTAL_COST,
+ 1.0000000001) < 0)
remove_old = true; /* new dominates old */
else
accept_new = false; /* old equals or dominates new */