diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2015-08-15 11:02:17 -0400 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2015-08-15 11:02:33 -0400 |
commit | 3218f8c33612baca0a1f44d4a243c598ddebad9d (patch) | |
tree | af3dd0d11d49545d01c598b53bbb5e6da08caae6 | |
parent | 8749aafde2179de243bc8ffeec23a28a94ec5def (diff) | |
download | postgresql-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.c | 50 |
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 */ |