Bug #116636 | Optimizer incorrectly ignores all indexes with NO_INDEX() in some cases | ||
---|---|---|---|
Submitted: | 13 Nov 5:25 | Modified: | 15 Nov 15:26 |
Reporter: | Joshua Varner | Email Updates: | |
Status: | Verified | Impact on me: | |
Category: | MySQL Server: Optimizer | Severity: | S2 (Serious) |
Version: | 8.4.3, 8.0.40, 9.1.0 | OS: | Any |
Assigned to: | CPU Architecture: | Any |
[13 Nov 5:25]
Joshua Varner
[13 Nov 8:37]
MySQL Verification Team
Hello Joshua Varner, Thank you for the report and test case. Verified as described. regards, Umesh
[13 Nov 15:43]
Joshua Varner
I also noticed that setting an index as invisible does not reproduce this behavior. An invisible index is still considered valid, so it does not trigger this issue. That's also somewhat troubling, actually, because making an index invisible prior to dropping is a safety mechanism that's often used to ensure the safety of dropping an index. It seems to me that invisible indexes should not be considered in the list of indexes to compare against at this stage.
[13 Nov 15:46]
Joshua Varner
To say more explicitly: I think an invisible index should also yield this unresolved name warning and behave exactly as though it's an invalid index name altogether; it seems like the whole point of setting an index as invisible, to hide it from the optimizer in as many phases as possible so that you're confident that behavior will be equivalent to dropping the index. I would expect the following SELECT statements to behave the same after setting idx_y to invisible: mysql [localhost:8034] {msandbox} (test) > ALTER TABLE foo ALTER INDEX idx_y INVISIBLE; Query OK, 0 rows affected (0.01 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql [localhost:8034] {msandbox} (test) > EXPLAIN SELECT /*+ NO_INDEX(foo idx_y) */ x FROM foo WHERE x = '2'; +----+-------------+-------+------------+------+---------------+-------+---------+-------+------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+-------+---------+-------+------+----------+-------------+ | 1 | SIMPLE | foo | NULL | ref | idx_x | idx_x | 1023 | const | 1 | 100.00 | Using index | +----+-------------+-------+------------+------+---------------+-------+---------+-------+------+----------+-------------+ 1 row in set, 1 warning (0.00 sec) mysql [localhost:8034] {msandbox} (test) > EXPLAIN SELECT /*+ NO_INDEX(foo idx_doesnt_exist) */ x FROM foo WHERE x = '2'; +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+ | 1 | SIMPLE | foo | NULL | ALL | NULL | NULL | NULL | NULL | 8 | 25.00 | Using where | +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+ 1 row in set, 2 warnings (0.00 sec) mysql [localhost:8034] {msandbox} (test) > show warnings; +---------+------+------------------------------------------------------------------------------------------------+ | Level | Code | Message | +---------+------+------------------------------------------------------------------------------------------------+ | Warning | 3128 | Unresolved name `foo`@`select#1` `idx_doesnt_exist` for NO_INDEX hint | | Note | 1003 | /* select#1 */ select `test`.`foo`.`x` AS `x` from `test`.`foo` where (`test`.`foo`.`x` = '2') | +---------+------+------------------------------------------------------------------------------------------------+ 2 rows in set (0.00 sec)
[15 Nov 15:26]
Joshua Varner
Similar issues seem to exist with NO_GROUP_INDEX, NO_JOIN_INDEX, and NO_ORDER_INDEX as well. I believe the code is filtering out invalid indexes, and in the end, that leaves the set empty. That then causes the logic to use all indexes instead, essentially making all of them ignored.