Bug #73046 | Optimizer chooses wrong plan with (const, range) order by range ASC | ||
---|---|---|---|
Submitted: | 19 Jun 2014 2:42 | Modified: | 19 Jun 2014 5:13 |
Reporter: | Morgan Tocker | Email Updates: | |
Status: | Verified | Impact on me: | |
Category: | MySQL Server: Optimizer | Severity: | S3 (Non-critical) |
Version: | 5.6.19 | OS: | Any |
Assigned to: | CPU Architecture: | Any |
[19 Jun 2014 2:42]
Morgan Tocker
[19 Jun 2014 5:13]
MySQL Verification Team
Hello Morgan, Thank you for the report and test case. Verified as described. Thanks, Umesh
[19 Jun 2014 5:28]
MySQL Verification Team
// 5.7.5 mysql> SELECT * FROM post WHERE post_id > 900000 and owner_id = 20 order by post_id DESC limit 10; # fast +---------+----------+------+ | post_id | owner_id | data | +---------+----------+------+ | 2424785 | 20 | data | | 2424531 | 20 | data | | 2424482 | 20 | data | | 2424383 | 20 | data | | 2424321 | 20 | data | | 2424066 | 20 | data | | 2423892 | 20 | data | | 2423791 | 20 | data | | 2423783 | 20 | data | | 2423778 | 20 | data | +---------+----------+------+ 10 rows in set (0.00 sec) mysql> SELECT * FROM post WHERE post_id > 900000 and owner_id = 20 order by post_id ASC limit 10; # slow +---------+----------+------+ | post_id | owner_id | data | +---------+----------+------+ | 900015 | 20 | data | | 900067 | 20 | data | | 900068 | 20 | data | | 900153 | 20 | data | | 900212 | 20 | data | | 900479 | 20 | data | | 900540 | 20 | data | | 900665 | 20 | data | | 900821 | 20 | data | | 900841 | 20 | data | +---------+----------+------+ 10 rows in set (0.13 sec) mysql> SELECT * FROM post WHERE post_id > 900000 and owner_id > 19 AND owner_id < 21 order by post_id ASC limit 10; # fast +---------+----------+------+ | post_id | owner_id | data | +---------+----------+------+ | 900015 | 20 | data | | 900067 | 20 | data | | 900068 | 20 | data | | 900153 | 20 | data | | 900212 | 20 | data | | 900479 | 20 | data | | 900540 | 20 | data | | 900665 | 20 | data | | 900821 | 20 | data | | 900841 | 20 | data | +---------+----------+------+ 10 rows in set (0.00 sec) mysql> EXPLAIN SELECT * FROM post WHERE post_id > 900000 and owner_id = 20 order by post_id ASC limit 10; # slow +----+-------------+-------+------------+-------------+---------------+---------------+---------+------+-------+----------+-------------------------------------------------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+-------------+---------------+---------------+---------+------+-------+----------+-------------------------------------------------------------+ | 1 | SIMPLE | post | NULL | index_merge | PRIMARY,my_fk | my_fk,PRIMARY | 12,4 | NULL | 14179 | 100.00 | Using intersect(my_fk,PRIMARY); Using where; Using filesort | +----+-------------+-------+------------+-------------+---------------+---------------+---------+------+-------+----------+-------------------------------------------------------------+ 1 row in set, 1 warning (0.00 sec) mysql> EXPLAIN SELECT * FROM post WHERE post_id > 900000 and owner_id > 19 AND owner_id < 21 order by post_id ASC limit 10; # fast +----+-------------+-------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+ | 1 | SIMPLE | post | NULL | range | PRIMARY,my_fk | PRIMARY | 4 | NULL | 1046240 | 100.00 | Using where | +----+-------------+-------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+ 1 row in set, 1 warning (0.00 sec)
[19 Jun 2014 7:11]
Øystein Grøvlen
This is clearly a bug in the range optimizer. Using index merge intersect when one of the indexes is a clustered primary key does not make sense. There is nothing to gain from scanning additional indexes in that case.
[10 Feb 2015 1:31]
Morgan Tocker
This appears to be fixed in 5.7.6 (using trunk build).
[11 Jun 2015 14:46]
Morgan Tocker
Pasting 5.7.7 results (all queries are fast): mysql [localhost] {msandbox} (test) > explain SELECT * FROM post WHERE post_id > 900000 and owner_id = 20 order by post_id DESC limit 10; # fast +----+-------------+-------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+ | 1 | SIMPLE | post | NULL | range | PRIMARY,my_fk | PRIMARY | 4 | NULL | 1046240 | 10.00 | Using where | +----+-------------+-------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+ 1 row in set, 1 warning (0.01 sec) mysql [localhost] {msandbox} (test) > explain SELECT * FROM post WHERE post_id > 900000 and owner_id = 20 order by post_id ASC limit 10; # slow +----+-------------+-------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+ | 1 | SIMPLE | post | NULL | range | PRIMARY,my_fk | PRIMARY | 4 | NULL | 1046240 | 10.00 | Using where | +----+-------------+-------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+ 1 row in set, 1 warning (0.00 sec) mysql [localhost] {msandbox} (test) > explain SELECT * FROM post WHERE post_id > 900000 and owner_id > 19 AND owner_id < 21 order by post_id ASC limit 10; # fast +----+-------------+-------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+ | 1 | SIMPLE | post | NULL | range | PRIMARY,my_fk | PRIMARY | 4 | NULL | 1046240 | 1.78 | Using where | +----+-------------+-------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+ 1 row in set, 1 warning (0.00 sec) mysql [localhost] {msandbox} (test) > select version(); +-----------+ | version() | +-----------+ | 5.7.7-rc | +-----------+
[17 Feb 2016 9:44]
Olav Sandstå
The change that makes the optimizer select the same query plan for all three cases and makes the problematic query run fast the implementation of the following worklog: WL#6986: Make switching of index due to small limit cost based This worklog was included in 5.7.6.
[17 Feb 2016 11:23]
Olav Sandstå
After the optimizer started to use range scan on the PRIMARY key for these queries, all queries complete quickly. But it would likely have been an even better choice if the optimizer selected to use range scan on the "my_fk" index. The optimizer should have been able to detect that this would be a better query plan.