summaryrefslogtreecommitdiff
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)
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 */