diff options
author | Tomas Vondra <tomas.vondra@postgresql.org> | 2019-11-28 22:20:28 +0100 |
---|---|---|
committer | Tomas Vondra <tomas.vondra@postgresql.org> | 2019-11-28 22:26:25 +0100 |
commit | ef3fed2ce4a3018a992ef913a3333bb682b702ae (patch) | |
tree | 449a28cf1ebb9f324df6f06475dbf2ed44ecd551 /src/backend/statistics/dependencies.c | |
parent | bf3cef24a31966686dfaae3085ce7c545c0019a4 (diff) |
Fix choose_best_statistics to check clauses individually
When picking the best extended statistics object for a list of clauses,
it's not enough to look at attnums extracted from the clause list as a
whole. Consider for example this query with OR clauses:
SELECT * FROM t WHERE (t.a = 1) OR (t.b = 1) OR (t.c = 1)
with a statistics defined on columns (a,b). Relying on attnums extracted
from the whole OR clause, we'd consider the statistics usable. That does
not work, as we see the conditions as a single OR-clause, referencing an
attribute not covered by the statistic, leading to empty list of clauses
to be estimated using the statistics and an assert failure.
This changes choose_best_statistics to check which clauses are actually
covered, and only using attributes from the fully covered ones. For the
previous example this means the statistics object will not be considered
as compatible with the OR-clause.
Backpatch to 12, where MCVs were introduced. The issue does not affect
older versions because functional dependencies don't handle OR clauses.
Author: Tomas Vondra
Reviewed-by: Dean Rasheed
Reported-By: Manuel Rigger
Discussion: https://postgr.es/m/CA+u7OA7H5rcE2=8f263w4NZD6ipO_XOrYB816nuLXbmSTH9pQQ@mail.gmail.com
Backpatch-through: 12
Diffstat (limited to 'src/backend/statistics/dependencies.c')
-rw-r--r-- | src/backend/statistics/dependencies.c | 26 |
1 files changed, 15 insertions, 11 deletions
diff --git a/src/backend/statistics/dependencies.c b/src/backend/statistics/dependencies.c index 585cad2ad94..560c1c9e845 100644 --- a/src/backend/statistics/dependencies.c +++ b/src/backend/statistics/dependencies.c @@ -951,14 +951,14 @@ dependencies_clauselist_selectivity(PlannerInfo *root, Bitmapset *clauses_attnums = NULL; StatisticExtInfo *stat; MVDependencies *dependencies; - AttrNumber *list_attnums; + Bitmapset **list_attnums; int listidx; /* check if there's any stats that might be useful for us. */ if (!has_stats_of_kind(rel->statlist, STATS_EXT_DEPENDENCIES)) return 1.0; - list_attnums = (AttrNumber *) palloc(sizeof(AttrNumber) * + list_attnums = (Bitmapset **) palloc(sizeof(Bitmapset *) * list_length(clauses)); /* @@ -981,11 +981,11 @@ dependencies_clauselist_selectivity(PlannerInfo *root, if (!bms_is_member(listidx, *estimatedclauses) && dependency_is_compatible_clause(clause, rel->relid, &attnum)) { - list_attnums[listidx] = attnum; + list_attnums[listidx] = bms_make_singleton(attnum); clauses_attnums = bms_add_member(clauses_attnums, attnum); } else - list_attnums[listidx] = InvalidAttrNumber; + list_attnums[listidx] = NULL; listidx++; } @@ -1002,8 +1002,8 @@ dependencies_clauselist_selectivity(PlannerInfo *root, } /* find the best suited statistics object for these attnums */ - stat = choose_best_statistics(rel->statlist, clauses_attnums, - STATS_EXT_DEPENDENCIES); + stat = choose_best_statistics(rel->statlist, STATS_EXT_DEPENDENCIES, + list_attnums, list_length(clauses)); /* if no matching stats could be found then we've nothing to do */ if (!stat) @@ -1043,16 +1043,22 @@ dependencies_clauselist_selectivity(PlannerInfo *root, foreach(l, clauses) { Node *clause; + AttrNumber attnum; listidx++; /* * Skip incompatible clauses, and ones we've already estimated on. */ - if (list_attnums[listidx] == InvalidAttrNumber) + if (!list_attnums[listidx]) continue; /* + * We expect the bitmaps ton contain a single attribute number. + */ + attnum = bms_singleton_member(list_attnums[listidx]); + + /* * Technically we could find more than one clause for a given * attnum. Since these clauses must be equality clauses, we choose * to only take the selectivity estimate from the final clause in @@ -1061,8 +1067,7 @@ dependencies_clauselist_selectivity(PlannerInfo *root, * anyway. If it happens to be compared to the same Const, then * ignoring the additional clause is just the thing to do. */ - if (dependency_implies_attribute(dependency, - list_attnums[listidx])) + if (dependency_implies_attribute(dependency, attnum)) { clause = (Node *) lfirst(l); @@ -1077,8 +1082,7 @@ dependencies_clauselist_selectivity(PlannerInfo *root, * We'll want to ignore this when looking for the next * strongest dependency above. */ - clauses_attnums = bms_del_member(clauses_attnums, - list_attnums[listidx]); + clauses_attnums = bms_del_member(clauses_attnums, attnum); } } |