【问题标题】:mysql difference in index usage between MyISAM and InnoDBMyISAM和InnoDB之间的mysql索引使用差异
【发布时间】:2013-04-08 02:26:00
【问题描述】:

我有这些小桌子,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

我已插入 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 |       |
+----+-------------+----------+--------+---------------+---------+---------+-------------------------+------+-------+

我的问题是,为什么处理索引的方式会有这种差异?

【问题讨论】:

标签: mysql indexing innodb myisam


【解决方案1】:

在 InnoDB 中,任何二级索引内部都包含表的主键列。所以列 (name) 上的索引 name 隐含在列 (name, id) 上。

这意味着 EXPLAIN 将您对类别表的访问显示为“索引扫描”(这在 type 列中显示为“索引”)。通过扫描索引,它还可以访问 id 列,用于在第二个表 item 中查找行。

然后它还利用 (category_id) 上的项目索引,它实际上是 (category_id, id),并且只需读取索引即可为您的选择列表获取 item.id。根本不需要阅读表格(这在 Extra 列中显示为“使用索引”)。

MyISAM 不会以这种方式存储主键和辅助键,因此无法获得相同的优化。对类别表的访问是“ALL”类型,表示表扫描。

我希望对 MyISAM 表项的访问将是“ref”,因为它使用 (category_id) 上的索引查找行。但是,如果表中的行数很少,或者自创建索引后您还没有完成ANALYZE TABLE item,优化器可能会得到不正确的结果。


您的更新:

看起来优化器更喜欢索引扫描而不是表扫描,所以它借此机会在 InnoDB 中进行索引扫描,并将类别表放在首位。优化器决定对表重新排序,而不是按照您在查询中给出的顺序使用这些表。

在 MyISAM 表中,无论它选择首先访问哪个表,都会进行一次表扫描,但是通过将类别表放在第二位,它会连接到类别的主键索引而不是项目的二级索引。与唯一键或主键(类型“eq_ref”)相比,优化器更喜欢查找。

【讨论】:

  • 你是对的,表格中的数据最少。我用 100 个类别和 1000 个项目填充它们并更新了我的问题。谢谢你的回答,很有启发性
  • @BillKarwin,mysql 为什么不能合并item 表的索引?有它需要的一切:id 和 category_id,即使 id 不包含在 KEY category_id 索引中,不像在 innodb 下
  • 通常 MySQL 在给定查询中每个表引用只使用一个索引。在某些情况下,它可以执行索引合并操作,但这种情况发生的次数比您想象的要少(请参阅dev.mysql.com/doc/refman/5.6/en/index-merge-optimization.html
猜你喜欢
  • 2012-09-06
  • 2012-04-14
  • 1970-01-01
  • 2011-12-20
  • 2011-10-28
  • 2012-03-01
  • 2012-10-02
  • 2011-05-14
  • 1970-01-01
相关资源
最近更新 更多