Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 732bfa2

Browse files
committed
Fix cost estimation for indexscan filter conditions.
cost_index's method for estimating per-tuple costs of evaluating filter conditions (a/k/a qpquals) was completely wrong in the presence of derived indexable conditions, such as range conditions derived from a LIKE clause. This was largely masked in common cases as a result of all simple operator clauses having about the same costs, but it could show up in a big way when dealing with functional indexes containing expensive functions, as seen for example in bug #6579 from Istvan Endredy. Rejigger the calculation to give sane answers when the indexquals aren't a subset of the baserestrictinfo list. As a side benefit, we now do the calculation properly for cases involving join clauses (ie, parameterized indexscans), which we always overestimated before. There are still cases where this is an oversimplification, such as clauses that can be dropped because they are implied by a partial index's predicate. But we've never accounted for that in cost estimates before, and I'm not convinced it's worth the cycles to try to do so.
1 parent 880bfc3 commit 732bfa2

File tree

1 file changed

+21
-19
lines changed

1 file changed

+21
-19
lines changed

src/backend/optimizer/path/costsize.c

+21-19
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ cost_index(IndexPath *path, PlannerInfo *root, double loop_count)
228228
IndexOptInfo *index = path->indexinfo;
229229
RelOptInfo *baserel = index->rel;
230230
bool indexonly = (path->path.pathtype == T_IndexOnlyScan);
231+
List *allclauses;
231232
Cost startup_cost = 0;
232233
Cost run_cost = 0;
233234
Cost indexStartupCost;
@@ -239,6 +240,7 @@ cost_index(IndexPath *path, PlannerInfo *root, double loop_count)
239240
spc_random_page_cost;
240241
Cost min_IO_cost,
241242
max_IO_cost;
243+
QualCost qpqual_cost;
242244
Cost cpu_per_tuple;
243245
double tuples_fetched;
244246
double pages_fetched;
@@ -267,8 +269,6 @@ cost_index(IndexPath *path, PlannerInfo *root, double loop_count)
267269
* Note that we force the clauses to be treated as non-join clauses
268270
* during selectivity estimation.
269271
*/
270-
List *allclauses;
271-
272272
allclauses = list_union_ptr(baserel->baserestrictinfo,
273273
path->indexclauses);
274274
path->path.rows = baserel->tuples *
@@ -283,6 +283,9 @@ cost_index(IndexPath *path, PlannerInfo *root, double loop_count)
283283
}
284284
else
285285
{
286+
/* allclauses should just be the rel's restriction clauses */
287+
allclauses = baserel->baserestrictinfo;
288+
286289
/*
287290
* The number of rows is the same as the parent rel's estimate, since
288291
* this isn't a parameterized path.
@@ -442,24 +445,23 @@ cost_index(IndexPath *path, PlannerInfo *root, double loop_count)
442445
/*
443446
* Estimate CPU costs per tuple.
444447
*
445-
* Normally the indexquals will be removed from the list of restriction
446-
* clauses that we have to evaluate as qpquals, so we should subtract
447-
* their costs from baserestrictcost. But if we are doing a join then
448-
* some of the indexquals are join clauses and shouldn't be subtracted.
449-
* Rather than work out exactly how much to subtract, we don't subtract
450-
* anything.
451-
*/
452-
startup_cost += baserel->baserestrictcost.startup;
453-
cpu_per_tuple = cpu_tuple_cost + baserel->baserestrictcost.per_tuple;
454-
455-
if (path->path.required_outer == NULL)
456-
{
457-
QualCost index_qual_cost;
448+
* What we want here is cpu_tuple_cost plus the evaluation costs of any
449+
* qual clauses that we have to evaluate as qpquals. We approximate that
450+
* list as allclauses minus any clauses appearing in indexquals (as
451+
* before, assuming that pointer equality is enough to recognize duplicate
452+
* RestrictInfos). This method neglects some considerations such as
453+
* clauses that needn't be checked because they are implied by a partial
454+
* index's predicate. It does not seem worth the cycles to try to factor
455+
* those things in at this stage, even though createplan.c will take pains
456+
* to remove such unnecessary clauses from the qpquals list if this path
457+
* is selected for use.
458+
*/
459+
cost_qual_eval(&qpqual_cost,
460+
list_difference_ptr(allclauses, path->indexquals),
461+
root);
458462

459-
cost_qual_eval(&index_qual_cost, path->indexquals, root);
460-
/* any startup cost still has to be paid ... */
461-
cpu_per_tuple -= index_qual_cost.per_tuple;
462-
}
463+
startup_cost += qpqual_cost.startup;
464+
cpu_per_tuple = cpu_tuple_cost + qpqual_cost.per_tuple;
463465

464466
run_cost += cpu_per_tuple * tuples_fetched;
465467

0 commit comments

Comments
 (0)