MySQL разница в использовании индекса между MyISAM и InnoDB

У меня есть эти маленькие таблицы item и category:

CREATE TABLE `item` (
  `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(150) NOT NULL,
  `category_id` mediumint(8) unsigned NOT NULL,
  PRIMARY KEY (`id`),
  KEY `name` (`name`),
  KEY `category_id` (`category_id`)
) CHARSET=utf8

CREATE TABLE `category` (
  `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(150) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `name` (`name`)
) CHARSET=utf8

Я вставил 100 категорий и 1000 элементов.

Если я запустил это:

EXPLAIN SELECT item.id,category.name AS category_name FROM item JOIN category ON item.category_id=category.id;

Затем, если движком таблиц является InnoDB, я получаю:

+----+-------------+----------+-------+---------------+-------------+---------+--------------------+------+-------------+
| id | select_type | table    | type  | possible_keys | key         | key_len | ref                | rows | Extra       |
+----+-------------+----------+-------+---------------+-------------+---------+--------------------+------+-------------+
|  1 | SIMPLE      | category | index | PRIMARY       | name        | 452     | NULL               |  103 | Using index |
|  1 | SIMPLE      | item     | ref   | category_id   | category_id | 3       | dbname.category.id |    5 | Using index |
+----+-------------+----------+-------+---------------+-------------+---------+--------------------+------+-------------+

В то время как, если я переключусь на MyISAM (с alter table engine=myisam), я получаю:

+----+-------------+----------+--------+---------------+---------+---------+-------------------------+------+-------+
| id | select_type | table    | type   | possible_keys | key     | key_len | ref                     | rows | Extra |
+----+-------------+----------+--------+---------------+---------+---------+-------------------------+------+-------+
|  1 | SIMPLE      | item     | ALL    | category_id   | NULL    | NULL    | NULL                    | 1003 |       |
|  1 | SIMPLE      | category | eq_ref | PRIMARY       | PRIMARY | 3       | dbname.item.category_id |    1 |       |
+----+-------------+----------+--------+---------------+---------+---------+-------------------------+------+-------+

У меня вопрос: почему такая разница в способах обработки индексов?


person periklis    schedule 15.04.2013    source источник
comment
Вы уверены, что вам не нужно также перестраивать индексы после механизма изменения?   -  person Sebas    schedule 16.04.2013
comment
согласно dev.mysql.com/doc/refman/5.0/ ru / rebuilding-tables.html, alter table engine - способ его перестроить. Тем не менее, я попытался сбросить и повторно импортировать таблицы, и результат был таким же (для myisam)   -  person periklis    schedule 16.04.2013


Ответы (1)


В InnoDB любой вторичный индекс внутри содержит столбец первичного ключа таблицы. Таким образом, индекс name в столбце (name) неявно указывается в столбцах (name, id).

Это означает, что EXPLAIN показывает ваш доступ к таблице категорий как «сканирование индекса» (это показано в столбце type как «index»). Сканируя индекс, он также получает доступ к столбцу id, который используется для поиска строк во второй таблице, item.

Затем он также использует индекс элемента на (category_id), который на самом деле (category_id, id), и может получить item.id для вашего списка выбора, просто прочитав индекс. Не нужно вообще читать таблицу (это показано в столбце Дополнительно как «Использование индекса»).

MyISAM не хранит первичные ключи с вторичным ключом таким образом, поэтому он не может получить такую ​​же оптимизацию. Доступ к таблице категорий осуществляется по типу «ВСЕ», что означает сканирование таблицы.

Я ожидал, что доступ к элементу таблицы MyISAM будет "ref", поскольку он ищет строки, используя индекс на (category_id). Но оптимизатор может получить искаженные результаты, если у вас очень мало строк в таблице или если вы не сделали ANALYZE TABLE item с момента создания индекса.


Повторите ваше обновление:

Похоже, что оптимизатор предпочитает сканирование индекса сканированию таблицы, поэтому он использует возможность выполнить сканирование индекса в InnoDB и ставит таблицу категорий первой. Оптимизатор решает переупорядочить таблицы вместо того, чтобы использовать таблицы в том порядке, в котором вы указали их в своем запросе.

В таблицах MyISAM будет одно сканирование таблицы, в зависимости от того, какая таблица будет выбрана для доступа первой, но, помещая таблицу категорий второй, она присоединяется к первичному ключевому индексу категории, а не к вторичному индексу элемента. Оптимизатор предпочитает поиск по уникальному или первичному ключу (тип «eq_ref»).

person Bill Karwin    schedule 15.04.2013
comment
Вы правы, в таблицах было минимум данных. Я заполнил их 100 категориями и 1000 элементами и обновил свой вопрос. Спасибо за ответ, поучительно - person periklis; 16.04.2013
comment
@BillKarwin, почему mysql не может объединить индексы таблицы item? Там есть все, что нужно: id и category_id, хотя id не включен в индекс KEY category_id в отличие от innodb - person Sebas; 16.04.2013
comment
Обычно MySQL использует только один индекс для каждой ссылки на таблицу в данном запросе. Бывают случаи, когда он может выполнять операцию слияния индексов, но это происходит реже, чем вы думаете (см. dev.mysql.com/doc/refman/5.6/en/index-merge-optimization.html) - person Bill Karwin; 16.04.2013