非常に奇妙な動作をする非常に単純な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 |
+--------+----------+
結果セットは、時間に基づいて、最低から最高の順になっていることに注意してください。さて、これをゲームのリーダーボードに使用しようとしているので、まさにそれがテーブルに実行させたいことです。クエリでexplainを実行すると、次のようになります。
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,
`time` time,
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 | |
+----+-------------+------------+------+---------------+------+---------+------+------+-------+
だから私が見つけようとしているのは、舞台裏で何が起こっているのかということです。主キーと別のインデックスがある場合、試行しなくてもインデックスで並べ替えられた結果セットを取得できるように見えるのはなぜですか。また、クエリオプティマイザーが主キーインデックスではなく他のインデックスを使用するのはなぜですか。