2014-05-25 5 views
1

Я прочитал несколько других вопросов о переполнении стека об этом сейчас, и это все еще не имеет смысла.MySQL не использует индекс для сортировки

Я экспериментировал с тестовой базой данных Sakila мира, вот мое определение таблицы:

CREATE TABLE `City` (
    `ID` int(11) NOT NULL AUTO_INCREMENT, 
    `Name` char(35) NOT NULL DEFAULT '', 
    `CountryCode` char(3) NOT NULL DEFAULT '', 
    `District` char(20) NOT NULL DEFAULT '', 
    `Population` int(11) NOT NULL DEFAULT '0', 
    PRIMARY KEY (`ID`), 
    KEY `CountryCode` (`CountryCode`), 
    KEY `city_name` (`Name`), 
    CONSTRAINT `city_ibfk_1` FOREIGN KEY (`CountryCode`) REFERENCES `Country` (`Code`) 
) ENGINE=InnoDB AUTO_INCREMENT=4080 DEFAULT CHARSET=latin1 

здесь мои индексы:

mysql> show index from City; 
+-------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | 
+-------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| City |   0 | PRIMARY  |   1 | ID   | A   |  4188 |  NULL | NULL |  | BTREE  |   |    | 
| City |   1 | CountryCode |   1 | CountryCode | A   |   465 |  NULL | NULL |  | BTREE  |   |    | 
| City |   1 | city_name |   1 | Name  | A   |  4188 |  NULL | NULL |  | BTREE  |   |    | 
+-------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 

Я пытаюсь понять, почему MySQL не использует индекс для сортировки результатов здесь:

mysql> explain select * from City order by Name asc; 
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+ 
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra   | 
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+ 
| 1 | SIMPLE  | City | ALL | NULL   | NULL | NULL | NULL | 4188 | Using filesort | 
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+ 

Я не понимаю, почему MySQL делает fileort в этом случай, довольно очевидно, что индекс в имени города уже отсортирован.

Я просмотрел некоторые другие вопросы, люди использовали префиксы в своем индексе, что запрещало MySQL использовать этот индекс для сортировки. Я не использовал префикс, когда создавал этот индекс по имени.

Также другие люди ожидали увидеть «Использование индекса» в столбце «Дополнительно». Я понимаю, что это означает, что индекс «охватывает» запрос, а это означает, что фактическую таблицу не нужно было читать, поскольку индекс имел все значения. Поэтому я не ожидаю увидеть это в столбце «Дополнительно», потому что индекс относится только к имени и есть другие столбцы.

Я чувствую, что термин «Использование индекса» немного вводит в заблуждение, MySQL может использовать индекс для фильтрации результатов, но все равно должен прочитать таблицу. В этом случае «Использование индекса» не будет частью столбца «Дополнительно». Слишком вводящий в заблуждение.

Может кто-нибудь объяснить мне, почему MySQL все еще использует файловый порт для этого запроса? На случай, если вы хотите знать, есть 4079 строк.

Также есть ли ясный способ узнать, что MySQL использовал индекс для сортировки результатов?

+0

Оптимизатор видит, что вы будете читать все записи из таблицы, поэтому он предпочитает чтение из индекса PRIMARY вместо вторичного city_name. Таким образом, MySQL должен выполнить дополнительную сортировку. – akuzminsky

ответ

0

Это ваш запрос:

select * 
from City 
order by Name asc; 

Есть две части этого запроса. Одна часть получает значения имен в правильном порядке. Другая часть отображает все остальные столбцы. MySQL должен сравнить стоимость этих двух операций.

Существует два возможных пути для запроса. Первый - взять все столбцы и отсортировать их по имени. Затем просто верните результаты. Это метод filesort. Во-вторых, чтобы прочитать индекс в порядке, а затем искать строки по одному в datatable.

MySQL решил, что первый метод выполняется быстрее. Это, очевидно, было бы правдой, если бы у вас была только одна строка (зачем читать индекс и строки, когда вы можете просто прочитать строку?). Я предполагаю, что у вас очень мало данных в таблице. По мере добавления дополнительных данных использование индекса будет более выгодным.

Как примечание, этот запрос должен вообще использовать индексный метод:

select Name 
from City 
order by Name asc; 
+0

Сколько строк требуется для MySQL, чтобы решить, что лучше использовать второй метод? У меня уже более 4000 строк в таблице. Таким образом, вы говорите, что сортировка 4000 строк занимает меньше времени, чем выборка строк из индекса. – msknapp

+0

Рассмотрите возможность сортировки любого набора из 4000 ключей с некоторой оптимизированной сортировкой. Время пренебрежимо мало. Передачи с диска намного дороже (подумайте, что вам нужно перенести структуру индекса и строки таблицы). Однако нет установленного числа, все зависит от эвристики, основанной на статистике и дизайне. 4000 строк - это абсолютно крошечные ряды чисел, все рассмотрено. – SystemFun

+0

@msknapp. , , 4 000 кажется достаточно большим, чтобы MySQL использовал индекс. Вопрос: Почему вы используете значения 'char()', а не 'varchar()'? Записи с фиксированной длиной больше и могут отбрасывать решение об оптимизации. –

0

Обычно, когда вы не решили фильтровать результаты (т.е. не где положение), СУБД решит использовать свой род/filter (в отличие от индекса) по причине, упомянутой выше.Ваша попытка вернуть всю информацию, относящуюся ко всем строкам в вашей таблице, которая более эффективно выполняется без использования индекса, учитывая, что для возврата данных, которые являются дополнительными к индексированному столбцу, необходимо выполнить поиск и передачу против таблицы, как только ключ находится в индексе.

Другими словами, индекс построен на выбранном вами поле, но не содержит никакой другой соответствующей информации о таблице ... Ergo, он должен ссылаться на истинное местоположение таблицы, чтобы получить дополнительные запрошенные метаданные, что менее эффективно, чем простая сортировка записей (учитывая, что у вас такой небольшой набор данных). Причиной этого является то, что быстрее процессор разумно сортировать небольшой набор данных в столбце (name), чем извлекать значения на основе вашего индекса, а затем сортировать их.

Часто, однако, индексы не используются при извлечении большого объема широкоформатных записей из таблицы сколь угодно большого размера по той причине, о которой я упоминал. Вы можете дать подсказки планировщика, которые заставят его использовать индекс для проверки того, что я упомянул здесь. Вы также можете увеличить свой набор данных на какой-то большой коэффициент, а затем попытаться выбрать меньшую его часть, чтобы проверить мои теория.

Смежные вопросы