一、SQL语句及执行计划
-
表结构
CREATE TABLE `t_10` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`a` int(11) DEFAULT NULL,
`b` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `a` (`a`),
KEY `b` (`b`)
) ENGINE=InnoDB AUTO_INCREMENT=803446 DEFAULT CHARSET=utf8;
-
SQL语句
mysql> select * from t_10 where (a between 1 and 1000) and (b between 50000 and 100000) order by b limit 1;
Empty set (0.34 sec)
-
SQL语句执行计划
mysql> explain select * from t_10 where (a between 1 and 1000) and (b between 50000 and 100000) order by b limit 1;
+----+-------------+-------+------------+-------+---------------+------+---------+------+--------+----------+------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+------+---------+------+--------+----------+------------------------------------+
| 1 | SIMPLE | t_10 | NULL | range | a,b | b | 5 | NULL | 329688 | 2.18 | Using index condition; Using where |
+----+-------------+-------+------------+-------+---------------+------+---------+------+--------+----------+------------------------------------+
从执行计划可以看出,该SQL走了扫描行数更多的b索引
二、原因分析
由于语句查询到结果后又需要对b字段再进行排序,而b字段本身有索引,已经是有序的,如果选择索引b的话,不需要再做排序,因此优化器走了b字段的索引(实际导致查询扫描行数更多耗时更久了)
三、SQL改写
-
改写后的SQL语句
mysql> select * from t_10 where (a between 1 and 1000) and (b between 50000 and 100000) order by b,a limit 1;
Empty set (0.01 sec)
-
改写后的执行计划
mysql> explain select * from t_10 where (a between 1 and 1000) and (b between 50000 and 100000) order by b,a limit 1;
+----+-------------+-------+------------+-------+---------------+------+---------+------+-------+----------+----------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+------+---------+------+-------+----------+----------------------------------------------------+
| 1 | SIMPLE | t_10 | NULL | range | a,b | a | 5 | NULL | 14398 | 50.00 | Using index condition; Using where; Using filesort |
+----+-------------+-------+------------+-------+---------------+------+---------+------+-------+----------+----------------------------------------------------+
显然,查询走了索引a,执行时间大大降低,并且扫描行数也减少了很多。
原因分析:当优化器发现a、b两个字段都需要排序时,会重点关注扫描行数,由于选择a索引扫描行数相对b索引少很多,因此走了索引a。