У меня есть следующая таблица 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 |
+----+-------------+-------+-------+---------------+---------+---------+------+---------+-------------+
Теперь, что действительно странно, так это то, что если я заставлю 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» в своем запросе, поэтому кажется, что для поиска идентификаторов нужно всего лишь сделать несколько прыжков по дереву, а затем использовать эти идентификаторы для получения заголовков из таблицы.
Что происходит?
РЕДАКТИРОВАТЬ: Больше информации о том, что я делаю:
- Кеш запросов отключен
- Запуск OPTIMIZE TABLE и ANALYZE TABLE не дал эффекта
- 6 620 372 строки имеют для is_active значение True. В 874 714 строках для параметра is_active установлено значение False.
- Использование FORCE INDEX (is_active) еще раз ускоряет запрос.
- MySQL версия 5.1.54