У меня есть следующая таблица MySQL (упрощенная):
CREATE TABLE `track` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(256) NOT NULL,
`is_active` tinyint(1) NOT NULL,
PRIMARY KEY (`id`),
KEY `is_active` (`is_active`, `id`)
) ENGINE=MyISAM AUTO_INCREMENT=7495088 DEFAULT CHARSET=utf8
Столбец 'is_active' помещает строки, которые я хочу игнорировать, в большинстве, но не всех, из моих запросов. У меня есть несколько запросов, которые периодически читают фрагменты из этой таблицы. Один из них выглядит следующим образом:
SELECT id,title from track where (track.is_active=1 and track.id > 5580702) ORDER BY id ASC LIMIT 10;
Этот запрос занимает более минуты, чтобы выполнить его. Здесь план выполнения:
> EXPLAIN SELECT id,title from track where (track.is_active=1 and track.id > 5580702) ORDER BY id ASC LIMIT 10;
+----+-------------+-------+------+----------------+--------+---------+-------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+----------------+--------+---------+-------+---------+-------------+
| 1 | SIMPLE | t | ref | PRIMARY,is_active | is_active | 1 | const | 3747543 | Using where |
+----+-------------+-------+------+----------------+--------+---------+-------+---------+-------------+
Теперь, если я говорю MySQL игнорировать индекс 'is_active', запрос выполняется мгновенно.
> EXPLAIN SELECT id,title from track IGNORE INDEX(is_active) WHERE (track.is_active=1 AND track.id > 5580702) ORDER BY id ASC LIMIT 10;
+----+-------------+-------+-------+---------------+---------+---------+------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+------+---------+-------------+
| 1 | SIMPLE | t | range | PRIMARY | PRIMARY | 4 | NULL | 1597518 | Using where |
+----+-------------+-------+-------+---------------+---------+---------+------+---------+-------------+
Теперь, что действительно странно, что если я FORCE MySQL использовать индекс is_active, запрос снова произойдет мгновенно!
+----+-------------+-------+-------+---------------+---------+---------+------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+------+---------+-------------+
| 1 | SIMPLE | t | range | is_active |is_active| 5 | NULL | 1866730 | Using where |
+----+-------------+-------+-------+---------------+---------+---------+------+---------+-------------+
Я просто не понимаю этого поведения. В индексе 'is_active' строки должны быть отсортированы с помощью is_active, за которым следует id. Я использую столбцы 'is_active' и 'id' в моем запросе, поэтому кажется, что для поиска идентификаторов нужно всего лишь несколько переходов по дереву, а затем использовать эти идентификаторы для извлечения заголовков из таблицы.
Что происходит?
EDIT: больше информации о том, что я делаю:
- Кэш запросов отключен.
- Запуск таблицы OPTIMIZE TABLE и ANALYZE TABLE не имел эффекта
- 6,620,372 строк имеют значение 'is_active' равным True. 874,714 строк имеют значение 'is_active' равным False.
- Использование FORCE INDEX (is_active) еще раз ускоряет запрос.
- Версия MySQL 5.1.54