Skip to content

Commit 9d6af73

Browse files
committed
Use fuzzy path cost tiebreaking rule in our oldest supported branches.
We've been doing it that way since 9.2, cf commit 33e9915, 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.
1 parent 24906bb commit 9d6af73

File tree

1 file changed

+29
-21
lines changed

1 file changed

+29
-21
lines changed

src/backend/optimizer/util/pathnode.c

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -92,44 +92,45 @@ compare_path_costs(Path *path1, Path *path2, CostSelector criterion)
9292
* same if they agree to within a "fuzz factor". This is used by add_path
9393
* to avoid keeping both of a pair of paths that really have insignificantly
9494
* different cost.
95+
*
96+
* The fuzz_factor argument must be 1.0 plus delta, where delta is the
97+
* fraction of the smaller cost that is considered to be a significant
98+
* difference. For example, fuzz_factor = 1.01 makes the fuzziness limit
99+
* be 1% of the smaller cost.
95100
*/
96101
static int
97-
compare_fuzzy_path_costs(Path *path1, Path *path2, CostSelector criterion)
102+
compare_fuzzy_path_costs(Path *path1, Path *path2, CostSelector criterion,
103+
double fuzz_factor)
98104
{
99-
/*
100-
* We use a fuzz factor of 1% of the smaller cost.
101-
*
102-
* XXX does this percentage need to be user-configurable?
103-
*/
104105
if (criterion == STARTUP_COST)
105106
{
106-
if (path1->startup_cost > path2->startup_cost * 1.01)
107+
if (path1->startup_cost > path2->startup_cost * fuzz_factor)
107108
return +1;
108-
if (path2->startup_cost > path1->startup_cost * 1.01)
109+
if (path2->startup_cost > path1->startup_cost * fuzz_factor)
109110
return -1;
110111

111112
/*
112113
* If paths have the same startup cost (not at all unlikely), order
113114
* them by total cost.
114115
*/
115-
if (path1->total_cost > path2->total_cost * 1.01)
116+
if (path1->total_cost > path2->total_cost * fuzz_factor)
116117
return +1;
117-
if (path2->total_cost > path1->total_cost * 1.01)
118+
if (path2->total_cost > path1->total_cost * fuzz_factor)
118119
return -1;
119120
}
120121
else
121122
{
122-
if (path1->total_cost > path2->total_cost * 1.01)
123+
if (path1->total_cost > path2->total_cost * fuzz_factor)
123124
return +1;
124-
if (path2->total_cost > path1->total_cost * 1.01)
125+
if (path2->total_cost > path1->total_cost * fuzz_factor)
125126
return -1;
126127

127128
/*
128129
* If paths have the same total cost, order them by startup cost.
129130
*/
130-
if (path1->startup_cost > path2->startup_cost * 1.01)
131+
if (path1->startup_cost > path2->startup_cost * fuzz_factor)
131132
return +1;
132-
if (path2->startup_cost > path1->startup_cost * 1.01)
133+
if (path2->startup_cost > path1->startup_cost * fuzz_factor)
133134
return -1;
134135
}
135136
return 0;
@@ -277,9 +278,11 @@ add_path(RelOptInfo *parent_rel, Path *new_path)
277278
/*
278279
* As of Postgres 8.0, we use fuzzy cost comparison to avoid wasting
279280
* cycles keeping paths that are really not significantly different in
280-
* cost.
281+
* cost. We use a 1% fuzziness limit. (XXX does this percentage need
282+
* to be user-configurable?)
281283
*/
282-
costcmp = compare_fuzzy_path_costs(new_path, old_path, TOTAL_COST);
284+
costcmp = compare_fuzzy_path_costs(new_path, old_path,
285+
TOTAL_COST, 1.01);
283286

284287
/*
285288
* If the two paths compare differently for startup and total cost,
@@ -292,7 +295,7 @@ add_path(RelOptInfo *parent_rel, Path *new_path)
292295
*/
293296
if (costcmp == 0 ||
294297
costcmp == compare_fuzzy_path_costs(new_path, old_path,
295-
STARTUP_COST))
298+
STARTUP_COST, 1.01))
296299
{
297300
switch (compare_pathkeys(new_path->pathkeys, old_path->pathkeys))
298301
{
@@ -305,11 +308,16 @@ add_path(RelOptInfo *parent_rel, Path *new_path)
305308
{
306309
/*
307310
* Same pathkeys, and fuzzily the same cost, so keep
308-
* just one --- but we'll do an exact cost comparison
309-
* to decide which.
311+
* just one; to decide which, do a fuzzy total-cost
312+
* comparison with very small fuzz limit. (We used to
313+
* do an exact cost comparison, but that results in
314+
* annoying platform-specific plan variations due to
315+
* roundoff in the cost estimates.) If things are
316+
* still tied, arbitrarily keep only the old path.
310317
*/
311-
if (compare_path_costs(new_path, old_path,
312-
TOTAL_COST) < 0)
318+
if (compare_fuzzy_path_costs(new_path, old_path,
319+
TOTAL_COST,
320+
1.0000000001) < 0)
313321
remove_old = true; /* new dominates old */
314322
else
315323
accept_new = false; /* old equals or dominates new */

0 commit comments

Comments
 (0)