Индекс MySQL datetime не работает

Структура таблицы:

+-------------+----------+------+-----+---------+----------------+
| Field       | Type     | Null | Key | Default | Extra          |
+-------------+----------+------+-----+---------+----------------+
| id          | int(11)  | NO   | PRI | NULL    | auto_increment |
| total       | int(11)  | YES  |     | NULL    |                |
| thedatetime | datetime | YES  | MUL | NULL    |                |
+-------------+----------+------+-----+---------+----------------+

Всего строк: 137967

mysql> explain select * from out where thedatetime <= NOW();
+----+-------------+-------------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table       | type | possible_keys | key  | key_len | ref  | rows   | Extra       |
+----+-------------+-------------+------+---------------+------+---------+------+--------+-------------+
|  1 | SIMPLE      | out         | ALL  | thedatetime   | NULL | NULL    | NULL | 137967 | Using where |
+----+-------------+-------------+------+---------------+------+---------+------+--------+-------------+

Реальный запрос намного длиннее с большим количеством объединений таблиц, дело в том, что я не могу заставить таблицу использовать индекс datetime. Это будет сложно для меня, если я хочу выбрать все данные до определенной даты. Тем не менее, я заметил, что я могу заставить MySQL использовать индекс, если я выбираю меньший поднабор данных.

mysql> explain select * from out where thedatetime <= '2008-01-01';
+----+-------------+-------------+-------+---------------+-------------+---------+------+-------+-------------+
| id | select_type | table       | type  | possible_keys | key         | key_len | ref  | rows  | Extra       |
+----+-------------+-------------+-------+---------------+-------------+---------+------+-------+-------------+
|  1 | SIMPLE      | out         | range | thedatetime   | thedatetime | 9       | NULL | 15826 | Using where |
+----+-------------+-------------+-------+---------------+-------------+---------+------+-------+-------------+

mysql> select count(*) from out where thedatetime <= '2008-01-01';
+----------+
| count(*) |
+----------+
|    15990 |
+----------+

Итак, что я могу сделать, чтобы MySQL использовал индекс независимо от того, какую дату я положил?

Ответы

Ответ 1

Все работает так, как предполагается.:)

Индексы для ускорения поиска. Они делают это, используя индексные запросы.

В первом запросе индекс не используется, потому что вы извлекаете ВСЕ строки, и в этом случае использование индекса медленнее (lookup index, get row, lookup index, get row... x количество строк медленнее, чем get all rows == сканирование таблицы)

Во втором запросе вы извлекаете только часть данных, и в этом случае сканирование таблицы происходит намного медленнее.

Задача оптимизатора - использовать статистику, которую RDBMS держит в индексе для определения наилучшего плана. В первом случае был рассмотрен индекс, но планировщик (правильно) отбросил его.

ИЗМЕНИТЬ
Вы можете прочитать что-то вроде this, чтобы получить некоторые понятия и ключевые слова в планировщике запросов mysql.

Ответ 2

Здесь есть две вещи -

  • Индекс не является достаточно избирательным - если индекс охватывает более ок. 30% строк, MySQL решит, что полное сканирование таблицы более эффективно. Когда вы сокращаете диапазон, индекс вступает.

  • Один индекс для таблицы в соединении

Реальный запрос намного длиннее с большим количеством таблиц, точка...

Точка именно потому, что у нее есть соединения, которые, вероятно, не могут использовать этот индекс. MySQL может использовать один индекс для каждой таблицы в объединении (если только он не соответствует index-merge оптимизации). Если первичный ключ уже используется для соединения, это время не будет использоваться. Чтобы использовать его, вам нужно создать индекс с несколькими столбцами в файле соединения + индекс времени в правильном порядке.

Проверьте EXPLAIN фактического запроса, чтобы узнать, какой ключ MySQL используется для соединения. Измените этот индекс, чтобы включить столбец thedatetime, или создайте новый индекс с несколькими столбцами от обоих (в зависимости от того, для чего вы используете ключ соединения).