8000 Clamp indexscan filter condition cost estimate to be not less than zero. · jandas/postgres@05504f1 · GitHub
[go: up one dir, main page]

Skip to content

Commit 05504f1

Browse files
committed
Clamp indexscan filter condition cost estimate to be not less than zero.
cost_index tries to estimate the per-tuple costs of evaluating filter conditions (a/k/a qpquals) by subtracting the estimated cost of the indexqual conditions from that of the baserestrictinfo conditions. This is correct so long as the indexquals list is a subset of the baserestrictinfo list. However, in the presence of derived indexable conditions it's completely wrong, leading to bogus or even negative scan cost estimates, as seen for example in bug #6579 from Istvan Endredy. In practice the problem isn't severe except in the specific case of a LIKE optimization on a functional index containing a very expensive function. A proper fix for this might change cost estimates by more than people would like for stable branches, so in the back branches let's just clamp the cost difference to be not less than zero. That will at least prevent completely insane behavior, while not changing the results normally.
1 parent 916eec2 commit 05504f1

File tree

1 file changed

+10
-1
lines changed

1 file changed

+10
-1
lines changed

src/backend/optimizer/path/costsize.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,14 @@ cost_index(IndexPath *path, PlannerInfo *root,
388388
* some of the indexquals are join clauses and shouldn't be subtracted.
389389
* Rather than work out exactly how much to subtract, we don't subtract
390390
* anything.
391+
*
392+
* XXX actually, this calculation is almost completely bogus, because
393+
* indexquals will contain derived indexable conditions which might be
394+
* quite different from the "original" quals in baserestrictinfo. We
395+
* ought to determine the actual qpqual list and cost that, rather than
396+
* using this shortcut. But that's too invasive a change to consider
397+
* back-patching, so for the moment we just mask the worst aspects of the
398+
* problem by clamping the subtracted amount.
391399
*/
392400
startup_cost += baserel->baserestrictcost.startup;
393401
cpu_per_tuple = cpu_tuple_cost + baserel->baserestrictcost.per_tuple;
@@ -398,7 +406,8 @@ cost_index(IndexPath *path, PlannerInfo *root,
398406

399407
cost_qual_eval(&index_qual_cost, indexQuals, root);
400408
/* any startup cost still has to be paid ... */
401-
cpu_per_tuple -= index_qual_cost.per_tuple;
409+
cpu_per_tuple -= Min(index_qual_cost.per_tuple,
410+
baserel->baserestrictcost.per_tuple);
402411
}
403412

404413
run_cost += cpu_per_tuple * tuples_fetched;

0 commit comments

Comments
 (0)
0