У меня есть прямая прямая таблица, которая в настоящее время имеет ~ 10M строк. Вот определение:Почему MySQL не использует индекс из EXPLAIN?
CREATE TABLE `train_run_messages` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`train_id` int(10) unsigned NOT NULL,
`customer_id` int(10) unsigned NOT NULL,
`station_id` int(10) unsigned NOT NULL,
`train_run_id` int(10) unsigned NOT NULL,
`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`type` tinyint(4) NOT NULL,
`customer_station_track_id` int(10) unsigned DEFAULT NULL,
`lateness_type` tinyint(3) unsigned NOT NULL,
`lateness_amount` mediumint(9) NOT NULL,
`lateness_code` tinyint(3) unsigned DEFAULT '0',
`info_text` varchar(32) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `timestamp` (`timestamp`),
KEY `lateness_amount` (`lateness_amount`),
KEY `customer_timestamp` (`customer_id`,`timestamp`),
KEY `trm_customer` (`customer_id`),
KEY `trm_train` (`train_id`),
KEY `trm_station` (`station_id`),
KEY `trm_trainrun` (`train_run_id`),
KEY `FI_trm_customer_station_tracks` (`customer_station_track_id`),
CONSTRAINT `FK_trm_customer_station_tracks` FOREIGN KEY (`customer_station_track_id`) REFERENCES `customer_station_tracks` (`id`),
CONSTRAINT `trm_customer` FOREIGN KEY (`customer_id`) REFERENCES `customers` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `trm_station` FOREIGN KEY (`station_id`) REFERENCES `stations` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `trm_train` FOREIGN KEY (`train_id`) REFERENCES `trains` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `trm_trainrun` FOREIGN KEY (`train_run_id`) REFERENCES `train_runs` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=9928724 DEFAULT CHARSET=utf8;
У нас есть много запросов, фильтр Customer_ID и метки времени, поэтому мы создали комбинированный индекс для этого.
Теперь у меня есть этот простой запрос:
SELECT * FROM `train_run_messages` WHERE `customer_id` = '5' AND `timestamp` >= '2013-12-01 00:00:57' AND `timestamp` <= '2013-12-31 23:59:59' LIMIT 0, 100
На нашей текущей машине с ~ записей 10Х этот запрос занимает ~ 16 секунд, что является способом долго в моем вкусе, так как есть индекс для запросов, таких как это.
Так давайте посмотрим на выходе объяснить этого запроса:
+----+-------------+--------------------+------+------------------------------------------- +--------------------+---------+-------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------------------+------+-------------------------------------------+--------------------+---------+-------+--------+-------------+
| 1 | SIMPLE | train_run_messages | ref | timestamp,customer_timestmap,trm_customer | customer_timestamp | 4 | const | 551405 | Using where |
+----+-------------+--------------------+------+-------------------------------------------+--------------------+---------+-------+--------+-------------+
Так MySQL говорит мне, что он будет использовать индекс customer_timestamp, отлично! Почему запрос все еще занимает ~ 16 секунд? Поскольку я не всегда доверяю анализатор запросов MySQL позволяет попробовать его с натянутой индекс:
SELECT * FROM `train_run_messages` USE INDEX (customer_timestamp) WHERE `customer_id` = '5' AND `timestamp` >= '2013-12-01 00:00:57' AND `timestamp` <= '2013-12-31 23:59:59' LIMIT 0, 100
запросов Время: 0.079s !!
Me: озадаченный!
Так может ли кто-нибудь объяснить, почему MySQL явно не использует индекс, который, по его словам, будет использоваться с выходом EXPLAIN? И есть ли способ доказать, какой индекс он действительно использовал при выполнении реального запроса?
Btw: Вот выход из медленного журнала:
# Time: 131217 11:18:04
# [email protected]: root[root] @ localhost [127.0.0.1]
# Query_time: 16.252878 Lock_time: 0.000168 Rows_sent: 100 Rows_examined: 9830711
SET timestamp=1387275484;
SELECT * FROM `train_run_messages` WHERE `customer_id` = '5' AND `timestamp` >= '2013-12-01 00:00:57' AND `timestamp` <= '2013-12-31 23:59:59' LIMIT 0, 100;
Alltough это конкретно не говорит, что он не использует какое-либо индексирование Rows_examined предполагает, что он делает полный просмотр таблицы.
Так это можно устранить без использования USE INDEX? Мы используем Propel в качестве ORM, и в настоящее время нет способа использовать «USE INDEX» для MySQL, без ручного ввода запроса.
Edit: Вот вывод EXPLAIN и USE INDEX:
+----+-------------+--------------------+-------+--------------------+--------------------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------------------+-------+--------------------+--------------------+---------+------+--------+-------------+
| 1 | SIMPLE | train_run_messages | range | customer_timestmap | customer_timestmap | 8 | NULL | 191264 | Using where |
+----+-------------+--------------------+-------+--------------------+--------------------+---------+------+--------+-------------+
Сколько различных идентификаторов клиентов существует? – Kickstart
В таблице train_run_messages есть только записи с customerId 5. (Система предназначена для нескольких клиентов, но в этой базе данных есть только один клиент) – Shyru
В этом случае он будет игнорировать индекс на customer_id (эмпирическое правило, оно похоже, если индекс не сужает записи ниже примерно 1/3, то он будет проигнорирован). Однако я бы ожидал, что временные штампы будут сужать его больше, чем это – Kickstart