diff options
author | Igor Babaev <igor@askmonty.org> | 2021-12-20 19:55:00 -0800 |
---|---|---|
committer | Igor Babaev <igor@askmonty.org> | 2021-12-23 19:12:58 -0800 |
commit | 42fea34d4a9f4ed1ae87cf8494f07bcdfcc49e83 (patch) | |
tree | f1ff39243949f6238bd9d25acf23313f3af41163 /sql | |
parent | b5cbe50604046647b52c1ed6b5af596483a120be (diff) | |
download | mariadb-git-42fea34d4a9f4ed1ae87cf8494f07bcdfcc49e83.tar.gz |
MDEV-27262 Unexpected index intersection with full index scan for an index
If when extracting a range condition for an index from the WHERE condition
Range Optimizer sees that the range condition covers the whole index then
such condition should be discarded because it cannot be used in any range
scan. In some cases Range Optimizer really does it, but there remained some
conditions for which it was not done. As a result the optimizer could
produce index merge plans with the full index scan for one of the indexes
participating in the index merge.
This could be observed in one of the test cases from index_merge1.inc
where a plan with index_merge_sort_union was produced and in the test case
reported for this bug where a plan with index_merge_sort_intersect was
produced. In both cases one of two index scans participating in index merge
ran over the whole index.
The patch slightly changes the original above mentioned test case from
index_merge1.inc to be able to produce an intended plan employing
index_merge_sort_union. The original query was left to show that index
merge is not used for it anymore.
It should be noted that for the plan with index_merge_sort_intersect could
be chosen for execution only due to a defect in the InnoDB code that
returns wrong estimates for the cardinality of big ranges.
This bug led to serious problems in 10.4+ where the optimization using
Rowid filters is employed (see mdev-26446).
Approved by Sergey Petrunia <sergey@mariadb.com>
Diffstat (limited to 'sql')
-rw-r--r-- | sql/opt_range.cc | 19 |
1 files changed, 18 insertions, 1 deletions
diff --git a/sql/opt_range.cc b/sql/opt_range.cc index f3f184367c9..89ee8cf98e1 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -9329,7 +9329,7 @@ key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1,SEL_ARG *key2) uint max_part_no= MY_MAX(key1->max_part_no, key2->max_part_no); - for (key2=key2->first(); key2; ) + for (key2=key2->first(); ; ) { /* key1 consists of one or more ranges. tmp is the range currently @@ -9343,6 +9343,16 @@ key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1,SEL_ARG *key2) ^ tmp */ + if (key1->min_flag & NO_MIN_RANGE && + key1->max_flag & NO_MAX_RANGE) + { + if (key1->maybe_flag) + return new SEL_ARG(SEL_ARG::MAYBE_KEY); + return 0; // Always true OR + } + if (!key2) + break; + SEL_ARG *tmp=key1->find_range(key2); /* @@ -9413,6 +9423,13 @@ key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1,SEL_ARG *key2) key2->copy_min(tmp); if (!(key1=key1->tree_delete(tmp))) { // Only one key in tree + if (key2->min_flag & NO_MIN_RANGE && + key2->max_flag & NO_MAX_RANGE) + { + if (key2->maybe_flag) + return new SEL_ARG(SEL_ARG::MAYBE_KEY); + return 0; // Always true OR + } key1=key2; key1->make_root(); key2=key2_next; |