1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-07 00:04:31 +03:00

MDEV-37292 Hint NO_INDEX() disables all indexes if none of given index names is resolved

When a hint has a list of index names, for example,
  `NO_INDEX(t1 idx1, idx2)`
there is a possibility that some or all of the listed index names will
not be resolved. If none of them are resolved, the hint becomes a table-level
hint, for example, `NO_INDEX(t1)`, which erroneously disables all indexes
of `t1` instead of disabling only some of them.

This commit addresses this issue by adding an additional check: a hint
containing a list of index names is considered resolved only when at least one
of the listed names is resolved successfully.
This commit is contained in:
Oleg Smirnov
2025-07-26 21:00:23 +07:00
committed by Sergei Golubchik
parent c329c43be7
commit 893761b35c
6 changed files with 175 additions and 9 deletions

View File

@@ -272,3 +272,96 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
Warnings:
Note 1003 delete /*+ NO_INDEX(`t1`@`select#1` `i_ab`) */ from `test`.`t1` using dual where `test`.`t1`.`a` = 1 and `test`.`t1`.`b` = 2 and `test`.`t1`.`c` = 3
DROP TABLE t1;
#
# Hint NO_INDEX() disables all indexes if none of given index names is not resolved
#
CREATE TABLE t1 (
a INT,
b INT,
PRIMARY KEY(a),
KEY ab(a, b)
);
INSERT INTO t1 VALUES (1,1),(2,2),(3,3),(4,4);
ANALYZE TABLE t1;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status OK
# By default, the index `ab` is used for grouping
EXPLAIN EXTENDED SELECT a FROM t1 GROUP BY a;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 range NULL ab 4 NULL 4 100.00 Using index for group-by
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` group by `test`.`t1`.`a`
# Invalid index names are ignored, index `ab` is still used
EXPLAIN EXTENDED SELECT /*+ NO_GROUP_INDEX(t1 bbb)*/ a FROM t1 GROUP BY a;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 range NULL ab 4 NULL 4 100.00 Using index for group-by
Warnings:
Warning 4222 Unresolved index name `t1`@`select#1` `bbb` for NO_GROUP_INDEX hint
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` group by `test`.`t1`.`a`
EXPLAIN EXTENDED SELECT /*+ NO_GROUP_INDEX(t1 bbb, abcd)*/ a FROM t1 GROUP BY a;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 range NULL ab 4 NULL 4 100.00 Using index for group-by
Warnings:
Warning 4222 Unresolved index name `t1`@`select#1` `bbb` for NO_GROUP_INDEX hint
Warning 4222 Unresolved index name `t1`@`select#1` `abcd` for NO_GROUP_INDEX hint
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` group by `test`.`t1`.`a`
EXPLAIN EXTENDED SELECT /*+ NO_GROUP_INDEX(t1 bbb, abcd, PRIMARY)*/ a FROM t1 GROUP BY a;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 range NULL ab 4 NULL 4 100.00 Using index for group-by
Warnings:
Warning 4222 Unresolved index name `t1`@`select#1` `bbb` for NO_GROUP_INDEX hint
Warning 4222 Unresolved index name `t1`@`select#1` `abcd` for NO_GROUP_INDEX hint
Note 1003 select /*+ NO_GROUP_INDEX(`t1`@`select#1` `bbb`,`abcd`,`PRIMARY`) */ `test`.`t1`.`a` AS `a` from `test`.`t1` group by `test`.`t1`.`a`
# This hint disables all indexes for grouping, so effectively it is the same
# as table-level hint NO_GROUP_INDEX(t1)
EXPLAIN EXTENDED SELECT /*+ NO_GROUP_INDEX(t1 bbb, dcba, PRIMARY, ab)*/ a FROM t1 GROUP BY a;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index; Using filesort
Warnings:
Warning 4222 Unresolved index name `t1`@`select#1` `bbb` for NO_GROUP_INDEX hint
Warning 4222 Unresolved index name `t1`@`select#1` `dcba` for NO_GROUP_INDEX hint
Note 1003 select /*+ NO_GROUP_INDEX(`t1`@`select#1` `bbb`,`dcba`,`PRIMARY`,`ab`) */ `test`.`t1`.`a` AS `a` from `test`.`t1` group by `test`.`t1`.`a`
# Compare the previous case with the table-level hint, results are the same:
EXPLAIN EXTENDED SELECT /*+ NO_GROUP_INDEX(t1)*/ a FROM t1 GROUP BY a;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index; Using filesort
Warnings:
Note 1003 select /*+ NO_GROUP_INDEX(`t1`@`select#1`) */ `test`.`t1`.`a` AS `a` from `test`.`t1` group by `test`.`t1`.`a`
# Same set of tests as above but for the global `NO_INDEX()` hint
EXPLAIN EXTENDED SELECT/*+ NO_INDEX(t1 bbb)*/ a FROM t1 GROUP BY a;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 range NULL ab 4 NULL 4 100.00 Using index for group-by
Warnings:
Warning 4222 Unresolved index name `t1`@`select#1` `bbb` for NO_INDEX hint
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` group by `test`.`t1`.`a`
EXPLAIN EXTENDED SELECT/*+ NO_INDEX(t1 bbb, abcd)*/ a FROM t1 GROUP BY a;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 range NULL ab 4 NULL 4 100.00 Using index for group-by
Warnings:
Warning 4222 Unresolved index name `t1`@`select#1` `bbb` for NO_INDEX hint
Warning 4222 Unresolved index name `t1`@`select#1` `abcd` for NO_INDEX hint
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` group by `test`.`t1`.`a`
EXPLAIN EXTENDED SELECT/*+ NO_INDEX(t1 bbb, abcd, PRIMARY)*/ a FROM t1 GROUP BY a;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 range NULL ab 4 NULL 4 100.00 Using index for group-by
Warnings:
Warning 4222 Unresolved index name `t1`@`select#1` `bbb` for NO_INDEX hint
Warning 4222 Unresolved index name `t1`@`select#1` `abcd` for NO_INDEX hint
Note 1003 select /*+ NO_INDEX(`t1`@`select#1` `bbb`,`abcd`,`PRIMARY`) */ `test`.`t1`.`a` AS `a` from `test`.`t1` group by `test`.`t1`.`a`
EXPLAIN EXTENDED SELECT/*+ NO_INDEX(t1 bbb, abcd, PRIMARY, ab)*/ a FROM t1 GROUP BY a;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 4 100.00 Using filesort
Warnings:
Warning 4222 Unresolved index name `t1`@`select#1` `bbb` for NO_INDEX hint
Warning 4222 Unresolved index name `t1`@`select#1` `abcd` for NO_INDEX hint
Note 1003 select /*+ NO_INDEX(`t1`@`select#1` `bbb`,`abcd`,`PRIMARY`,`ab`) */ `test`.`t1`.`a` AS `a` from `test`.`t1` group by `test`.`t1`.`a`
EXPLAIN EXTENDED SELECT/*+ NO_INDEX(t1)*/ a FROM t1 GROUP BY a;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 4 100.00 Using filesort
Warnings:
Note 1003 select /*+ NO_INDEX(`t1`@`select#1`) */ `test`.`t1`.`a` AS `a` from `test`.`t1` group by `test`.`t1`.`a`
DROP TABLE t1;
#
# End of 12.1 tests
#

View File

@@ -112,3 +112,48 @@ EXPLAIN EXTENDED DELETE FROM t1 WHERE a = 1 AND b = 2 AND c = 3;
EXPLAIN EXTENDED DELETE /*+ NO_INDEX(t1 i_ab) */ FROM t1 WHERE a = 1 AND b = 2 AND c = 3;
DROP TABLE t1;
--echo #
--echo # Hint NO_INDEX() disables all indexes if none of given index names is not resolved
--echo #
CREATE TABLE t1 (
a INT,
b INT,
PRIMARY KEY(a),
KEY ab(a, b)
);
INSERT INTO t1 VALUES (1,1),(2,2),(3,3),(4,4);
ANALYZE TABLE t1;
# Warnings "Unresolved table/index name..." are generated during both prepare
# and execution stages. So disable PS protocol to avoid duplication
--disable_ps_protocol
--echo # By default, the index `ab` is used for grouping
EXPLAIN EXTENDED SELECT a FROM t1 GROUP BY a;
--echo # Invalid index names are ignored, index `ab` is still used
EXPLAIN EXTENDED SELECT /*+ NO_GROUP_INDEX(t1 bbb)*/ a FROM t1 GROUP BY a;
EXPLAIN EXTENDED SELECT /*+ NO_GROUP_INDEX(t1 bbb, abcd)*/ a FROM t1 GROUP BY a;
EXPLAIN EXTENDED SELECT /*+ NO_GROUP_INDEX(t1 bbb, abcd, PRIMARY)*/ a FROM t1 GROUP BY a;
--echo # This hint disables all indexes for grouping, so effectively it is the same
--echo # as table-level hint NO_GROUP_INDEX(t1)
EXPLAIN EXTENDED SELECT /*+ NO_GROUP_INDEX(t1 bbb, dcba, PRIMARY, ab)*/ a FROM t1 GROUP BY a;
--echo # Compare the previous case with the table-level hint, results are the same:
EXPLAIN EXTENDED SELECT /*+ NO_GROUP_INDEX(t1)*/ a FROM t1 GROUP BY a;
--echo # Same set of tests as above but for the global `NO_INDEX()` hint
EXPLAIN EXTENDED SELECT/*+ NO_INDEX(t1 bbb)*/ a FROM t1 GROUP BY a;
EXPLAIN EXTENDED SELECT/*+ NO_INDEX(t1 bbb, abcd)*/ a FROM t1 GROUP BY a;
EXPLAIN EXTENDED SELECT/*+ NO_INDEX(t1 bbb, abcd, PRIMARY)*/ a FROM t1 GROUP BY a;
EXPLAIN EXTENDED SELECT/*+ NO_INDEX(t1 bbb, abcd, PRIMARY, ab)*/ a FROM t1 GROUP BY a;
EXPLAIN EXTENDED SELECT/*+ NO_INDEX(t1)*/ a FROM t1 GROUP BY a;
--enable_ps_protocol
DROP TABLE t1;
--echo #
--echo # End of 12.1 tests
--echo #

View File

@@ -552,14 +552,6 @@ bool Opt_hints_table::fix_key_hints(TABLE *table)
fixing the child objects.
*/
set_fixed();
if (is_specified(INDEX_HINT_ENUM))
global_index_map.set_fixed();
if (is_specified(JOIN_INDEX_HINT_ENUM))
join_index_map.set_fixed();
if (is_specified(GROUP_INDEX_HINT_ENUM))
group_index_map.set_fixed();
if (is_specified(ORDER_INDEX_HINT_ENUM))
order_index_map.set_fixed();
/* Make sure that adjustment is called only once. */
DBUG_ASSERT(keyinfo_array.size() == 0);
@@ -582,6 +574,26 @@ bool Opt_hints_table::fix_key_hints(TABLE *table)
}
}
/*
Fixing compound index hints. A compound hint is fixed in two cases:
- it is a table-level hint, i.e. does not have a list of index names
(like ORDER_INDEX(t1);
- it has a list of index names, and at least one of listed
index names is resolved successfully. So, NO_INDEX(t1 bad_idx) does not
become a table-level hint NO_INDEX(t1) if `bad_idx` cannnot be resolved.
*/
for (opt_hints_enum
hint_type : { INDEX_HINT_ENUM, JOIN_INDEX_HINT_ENUM,
GROUP_INDEX_HINT_ENUM, ORDER_INDEX_HINT_ENUM })
{
if (is_specified(hint_type))
{
Opt_hints_key_bitmap *bitmap= get_key_hint_bitmap(hint_type);
if (bitmap->is_table_level() || bitmap->bits_set() > 0)
bitmap->set_fixed();
}
}
if (are_children_fully_fixed())
return false;

View File

@@ -648,10 +648,12 @@ public:
void set_fixed() { fixed= true; }
bool is_fixed() const { return fixed; }
bool is_table_level() const { return parsed_hint->is_table_level_hint(); }
void set_key_map(uint i) { key_map.set_bit(i); }
bool is_set_key_map(uint i) { return key_map.is_set(i); }
bool is_key_map_clear_all() { return key_map.is_clear_all(); }
uint bits_set() { return key_map.bits_set(); }
Key_map *get_key_map() { return &key_map; }
};

View File

@@ -588,7 +588,13 @@ bool Parser::Index_level_hint::resolve(Parse_context *pc) const
const Lex_ident_sys key_conflict(
STRING_WITH_LEN("another hint was already specified for this index"));
if (is_empty()) // Empty list of index names, i.e. it is a table level hint
/*
If no index names are given, this is a table level hint, for example:
GROUP_INDEX(t1), NO_MRR(t2).
Otherwise this is a group of index-level hints:
NO_INDEX(t1 idx1, idx2) NO_ICP(t2 idx_a, idx_b, idx_c)
*/
if (is_empty())
{
uint warn_code= 0;
if (is_compound_hint(hint_type) &&

View File

@@ -656,6 +656,14 @@ public:
public:
using AND4::AND4;
/*
If no index names are given, this is a table level hint, for example:
GROUP_INDEX(t1), NO_MRR(t2).
Otherwise this is an index-level hints:
NO_INDEX(t1 idx1, idx2) NO_ICP(t2 idx_a, idx_b, idx_c)
*/
bool is_table_level_hint() const { return is_empty(); }
bool resolve(Parse_context *pc) const;
void append_args(THD *thd, String *str) const override;
};