简体   繁体   English

mysql在MyISAM和InnoDB之间的索引使用差异

[英]mysql difference in index usage between MyISAM and InnoDB

I have these small tables, item and category : 我有这些小桌子, itemcategory

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

I have inserted 100 categories and 1000 items. 我插入了100个类别和1000个项目。

If I run this: 如果我运行这个:

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

Then, if the tables' engine is InnoDB I get: 然后,如果表的引擎是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 |
+----+-------------+----------+-------+---------------+-------------+---------+--------------------+------+-------------+

Whereas, if I switch to MyISAM (with alter table engine=myisam ) I get: 然而,如果我切换到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 |       |
+----+-------------+----------+--------+---------------+---------+---------+-------------------------+------+-------+

My question is, why this difference in the way indexes are handled? 我的问题是,为什么处理索引的方式存在差异?

In InnoDB, any secondary index internally contains the primary key column of the table. 在InnoDB中,任何辅助索引内部都包含表的主键列。 So the index name on column (name) is implicitly on columns (name, id). 因此列(名称)上的索引名称隐含在列(name,id)上。

This means that EXPLAIN shows your access to the category table as an "index-scan" (this is shown in the type column as "index"). 这意味着EXPLAIN将您对类别表的访问权限显示为“索引扫描”(这在类型列中显示为“索引”)。 By scanning the index, it also has access to the id column, which it uses to look up rows in the second table, item. 通过扫描索引,它还可以访问id列,它用于查找第二个表item中的行。

Then it also takes advantage of the item index on (category_id) which is really (category_id, id), and it is able to fetch item.id for your select-list simply by reading the index. 然后它还利用了(category_id)上的项索引,它实际上是(category_id,id),只需通过读取索引就可以为select-list获取item.id。 No need to read the table at all (this is shown in the Extra column as "Using index"). 根本不需要读取该表(这在Extra列中显示为“Using index”)。

MyISAM doesn't store primary keys with the secondary key in this way, so it can't get the same optimizations. MyISAM不以这种方式使用辅助密钥存储主键,因此无法获得相同的优化。 The access to the category table is type "ALL" which means a table-scan. 对类别表的访问是“ALL”类型,表示表扫描。

I would expect the access to the MyISAM table item would be "ref" as it looks up rows using the index on (category_id). 我期望对MyISAM表项的访问将是“ref”,因为它使用(category_id)上的索引查找行。 But the optimizer may get skewed results if you have very few rows in the table, or if you haven't done ANALYZE TABLE item since creating the index. 但是如果表中的行数很少,或者自创建索引以来没有完成ANALYZE TABLE item ,优化程序可能会得到偏差的结果。


Re your update: 重新更新:

It looks like the optimizer prefers an index-scan over a table-scan, so it takes the opportunity to do an index-scan in InnoDB, and puts the category table first. 看起来优化器更喜欢对表扫描进行索引扫描,因此它有机会在InnoDB中进行索引扫描,并将类别表放在第一位。 The optimizer decides to re-order the tables instead of using the tables in the order you gave them in your query. 优化程序决定重新排序表,而不是按照查询中给出的顺序使用表。

In the MyISAM tables, there will be one table-scan whichever table it chooses to access first, but by putting the category table second, it joins to category's PRIMARY key index instead of item's secondary index. 在MyISAM表中,将有一个表扫描它首先选择访问哪个表,但是通过将类别表放在第二个,它将连接到类别的PRIMARY键索引而不是item的辅助索引。 The optimizer prefers lookups to a unique or primary key (type "eq_ref"). 优化器更喜欢查找唯一键或主键(键入“eq_ref”)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM