我有一个非常简单的MySQL表,有一些非常奇怪的行为.顺便说一下,奇怪的行为正是我想要它做的,但我不想把它投入生产,不知道为什么它做它做的事情.
无论如何,我有一个像这样的表:
Create table `raceTimes` (
`userID` mediumint(8) unsigned,`time` time,primary key (`userID`),key `idx_time` (`time`)
) engine=InnoDB default charset=utf8;
现在,当我从raceTimes查询中执行Select *时,我得到如下结果集:
MysqL> Select * from raceTimes;
+--------+----------+
| userID | time |
+--------+----------+
| 14 | 12:37:46 |
| 6 | 12:41:11 |
| 5 | 12:48:45 |
| 13 | 12:55:46 |
| 10 | 13:13:37 |
| 9 | 13:40:37 |
| 17 | 15:30:44 |
| 18 | 15:46:58 |
| 3 | 16:16:45 |
| 8 | 16:40:11 |
| 7 | 16:41:11 |
| 4 | 16:48:45 |
| 16 | 20:30:44 |
| 15 | 20:37:44 |
| 1 | 21:00:00 |
| 2 | 21:16:00 |
| 11 | 23:13:37 |
| 20 | 23:14:58 |
| 19 | 23:46:58 |
| 12 | 23:55:46 |
+--------+----------+
请注意,结果集是基于时间的顺序,从最低到最高.好吧,所以这正是我想要表格所做的事情,因为我试图将它用于游戏中的排行榜.当我对我的查询运行解释时,我得到了这个:
MysqL> explain select * from raceTimes;
+----+-------------+------------+-------+---------------+----------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+-------+---------------+----------+---------+------+------+-------------+
| 1 | SIMPLE | raceTimes | index | NULL | idx_time | 4 | NULL | 20 | Using index |
+----+-------------+------------+-------+---------------+----------+---------+------+------+-------------+
到目前为止一切都很棒.由于idx_time索引被排序(因为索引是),我得到了一个排序结果集,为此我正在点击一个索引.现在为了奇怪的行为.
根据我的阅读,主键在默认情况下被索引,并且在查询表时应该是最快的索引.然而它没被使用.我的猜测是idx_time索引小于主键索引,因为它是一个时间类型而不是mediumint(8)类型.但这只是猜测.
现在,如果我创建一个与上面创建的表相同的表,但省略主键,如下所示:
Create table `raceTimes2` (
`userID` mediumint(8) unsigned,key `idx_time` (`time`)
) engine=InnoDB default charset=utf8;
然后结果集不会在此时间列上排序.即使我告诉它在我的查询中专门使用idx_time索引,这种行为仍然存在.另外,如果我对查询做了解释,我会得到这个:
MysqL> explain select * from testTable6 use index(`idx_time`);
+----+-------------+------------+------+---------------+------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+---------------+------+---------+------+------+-------+
| 1 | SIMPLE | raceTimes2 | ALL | NULL | NULL | NULL | NULL | 20 | |
+----+-------------+------------+------+---------------+------+---------+------+------+-------+
所以我想要找出的是幕后发生的事情.为什么看起来如果我有一个主键和另一个索引,我可以得到一个在索引上排序的结果集,甚至没有尝试,为什么查询优化器会使用其他索引而不是主键索引?
在第一种情况下,MysqL仅使用idx_time索引执行查询,而不打开实际的表.当您使用的所有列都在索引中时,这是可能的(InnoDB表的主键始终附加到每个索引的末尾,因此您的索引在幕后是实际的(time,userID)).结果按时间排序,因为这是时间索引中的实际顺序.
在第二种情况下,列userID不是任何索引的一部分,MysqL必须进行常规表扫描才能获取结果. “use index(idx_time)”在这种情况下不执行任何操作,因为没有使用time列的WHERE子句.
编辑:
它仅在有选择时才适用,但如果不能使用USE INDEX中指定的索引,MysqL将不会使用该表上的任何索引进行搜索(WHERE / ON子句)并将读取整个表.因此在使用索引提示时应该非常小心.
解释为type =’index’的行也意味着将读取表中的所有行,并且几乎与type =’ALL’一样糟糕.
您应该查看index hints和explain output上的MysqL手册.