@@ -92,44 +92,45 @@ compare_path_costs(Path *path1, Path *path2, CostSelector criterion)
92
92
* same if they agree to within a "fuzz factor". This is used by add_path
93
93
* to avoid keeping both of a pair of paths that really have insignificantly
94
94
* 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.
95
100
*/
96
101
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 )
98
104
{
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
- */
104
105
if (criterion == STARTUP_COST )
105
106
{
106
- if (path1 -> startup_cost > path2 -> startup_cost * 1.01 )
107
+ if (path1 -> startup_cost > path2 -> startup_cost * fuzz_factor )
107
108
return +1 ;
108
- if (path2 -> startup_cost > path1 -> startup_cost * 1.01 )
109
+ if (path2 -> startup_cost > path1 -> startup_cost * fuzz_factor )
109
110
return -1 ;
110
111
111
112
/*
112
113
* If paths have the same startup cost (not at all unlikely), order
113
114
* them by total cost.
114
115
*/
115
- if (path1 -> total_cost > path2 -> total_cost * 1.01 )
116
+ if (path1 -> total_cost > path2 -> total_cost * fuzz_factor )
116
117
return +1 ;
117
- if (path2 -> total_cost > path1 -> total_cost * 1.01 )
118
+ if (path2 -> total_cost > path1 -> total_cost * fuzz_factor )
118
119
return -1 ;
119
120
}
120
121
else
121
122
{
122
- if (path1 -> total_cost > path2 -> total_cost * 1.01 )
123
+ if (path1 -> total_cost > path2 -> total_cost * fuzz_factor )
123
124
return +1 ;
124
- if (path2 -> total_cost > path1 -> total_cost * 1.01 )
125
+ if (path2 -> total_cost > path1 -> total_cost * fuzz_factor )
125
126
return -1 ;
126
127
127
128
/*
128
129
* If paths have the same total cost, order them by startup cost.
129
130
*/
130
- if (path1 -> startup_cost > path2 -> startup_cost * 1.01 )
131
+ if (path1 -> startup_cost > path2 -> startup_cost * fuzz_factor )
131
132
return +1 ;
132
- if (path2 -> startup_cost > path1 -> startup_cost * 1.01 )
133
+ if (path2 -> startup_cost > path1 -> startup_cost * fuzz_factor )
133
134
return -1 ;
134
135
}
135
136
return 0 ;
@@ -277,9 +278,11 @@ add_path(RelOptInfo *parent_rel, Path *new_path)
277
278
/*
278
279
* As of Postgres 8.0, we use fuzzy cost comparison to avoid wasting
279
280
* 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?)
281
283
*/
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 );
283
286
284
287
/*
285
288
* If the two paths compare differently for startup and total cost,
@@ -292,7 +295,7 @@ add_path(RelOptInfo *parent_rel, Path *new_path)
292
295
*/
293
296
if (costcmp == 0 ||
294
297
costcmp == compare_fuzzy_path_costs (new_path , old_path ,
295
- STARTUP_COST ))
298
+ STARTUP_COST , 1.01 ))
296
299
{
297
300
switch (compare_pathkeys (new_path -> pathkeys , old_path -> pathkeys ))
298
301
{
@@ -305,11 +308,16 @@ add_path(RelOptInfo *parent_rel, Path *new_path)
305
308
{
306
309
/*
307
310
* 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.
310
317
*/
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 )
313
321
remove_old = true; /* new dominates old */
314
322
else
315
323
accept_new = false; /* old equals or dominates new */
0 commit comments