Skip to content

Commit 7adbe18

Browse files
committed
Avoid believing incomplete MCV-only stats in get_variable_range().
get_variable_range() would incautiously believe that statistics containing only an MCV list are sufficient to derive a range estimate. That's okay for an enum-like column that contains only MCVs, but otherwise the estimate could be pretty bad. Make it report that the range is indeterminate unless the MCVs plus nullfrac account for the whole table. I don't think this needs a dedicated test case, since a quick code coverage check verifies that the existing regression tests traverse all the alternatives. There is room to doubt that a future-proof test case could be built anyway, given that the submitted example accidentally doesn't fail before v11. Per bug #17207 from Simon Perepelitsa. Back-patch to v10. In principle this has been broken all along, but I'm hesitant to make such changes in 9.6, since if anyone is unhappy with 9.6.24's behavior there will be no second chance to fix it. Discussion: https://postgr.es/m/17207-5265aefa79e333b4@postgresql.org
1 parent 04ef202 commit 7adbe18

File tree

1 file changed

+25
-5
lines changed

1 file changed

+25
-5
lines changed

src/backend/utils/adt/selfuncs.c

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5494,15 +5494,35 @@ get_variable_range(PlannerInfo *root, VariableStatData *vardata,
54945494
/*
54955495
* If we have most-common-values info, look for extreme MCVs. This is
54965496
* needed even if we also have a histogram, since the histogram excludes
5497-
* the MCVs.
5497+
* the MCVs. However, if we *only* have MCVs and no histogram, we should
5498+
* be pretty wary of deciding that that is a full representation of the
5499+
* data. Proceed only if the MCVs represent the whole table (to within
5500+
* roundoff error).
54985501
*/
54995502
if (get_attstatsslot(&sslot, vardata->statsTuple,
55005503
STATISTIC_KIND_MCV, InvalidOid,
5501-
ATTSTATSSLOT_VALUES))
5504+
have_data ? ATTSTATSSLOT_VALUES :
5505+
(ATTSTATSSLOT_VALUES | ATTSTATSSLOT_NUMBERS)))
55025506
{
5503-
get_stats_slot_range(&sslot, opfuncoid, &opproc,
5504-
collation, typLen, typByVal,
5505-
&tmin, &tmax, &have_data);
5507+
bool use_mcvs = have_data;
5508+
5509+
if (!have_data)
5510+
{
5511+
double sumcommon = 0.0;
5512+
double nullfrac;
5513+
int i;
5514+
5515+
for (i = 0; i < sslot.nnumbers; i++)
5516+
sumcommon += sslot.numbers[i];
5517+
nullfrac = ((Form_pg_statistic) GETSTRUCT(vardata->statsTuple))->stanullfrac;
5518+
if (sumcommon + nullfrac > 0.99999)
5519+
use_mcvs = true;
5520+
}
5521+
5522+
if (use_mcvs)
5523+
get_stats_slot_range(&sslot, opfuncoid, &opproc,
5524+
collation, typLen, typByVal,
5525+
&tmin, &tmax, &have_data);
55065526
free_attstatsslot(&sslot);
55075527
}
55085528

0 commit comments

Comments
 (0)