MySQL没有使用索引排序

时间:2014-05-25 03:27:01

标签: mysql indexing

我现在已经阅读了其他几个关于此问题的堆栈溢出问题,但它仍然没有意义。

我正在试验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在这种情况下正在进行文件分析,很明显城市名称上的索引已经对所有内容进行了排序。

我查了一些其他问题,人们在他们的索引中使用了前缀,这禁止MySQL使用该索引进行排序。我在名字上创建索引时没有使用前缀。

其他人也期望看到"使用索引"在Extra列中。我的理解是,这意味着指数涵盖了'查询,意味着不需要读取实际表,因为索引具有所有值。所以我不希望在Extra列中看到它,因为索引仅在名称上,还有其他列。

我觉得这个术语"使用索引"有点误导,MySQL可以使用索引来过滤结果,但仍然需要读取表。在这种情况下,"使用索引"不会成为Extra列的一部分。太误导了。

有人可以向我解释为什么MySQL还在为该查询使用文件排序吗?如果你想知道,有4079行。

另外,有没有明确的方法可以知道MySQL使用索引对结果进行排序?

2 个答案:

答案 0 :(得分:0)

这是您的查询:

select *
from City 
order by Name asc;

此查询分为两部分。一部分是以正确的顺序获取名称值。另一部分是获取所有其他列。 MySQL必须比较这两个操作的成本。

查询有两种可能的路径。第一种是获取所有列并按名称对它们进行排序。然后只返回结果。这是filesort方法。第二种是按顺序读取索引,然后在数据表中逐个查找行。

MySQL已经确定第一种方法更快。如果你只有一行(为什么在读取行时读取索引行?),这显然是正确的。我的猜测是你表中的数据非常少。随着您添加更多数据,使用索引将更有益。

注意,此查询通常应使用索引方法:

select Name
from City 
order by Name asc;

答案 1 :(得分:0)

通常,当您不决定过滤结果时(即没有where子句),RDBMS将决定使用排序/过滤方法(而不是索引),原因如上所述。您尝试返回与表中所有行有关的所有信息,这可以更有效地完成而不使用索引,为了返回索引列之外的数据,必须进行查找和传输一旦在索引中找到了密钥,就可以反对该表。

换句话说,索引建立在您选择的字段上,但不包含有关该表的任何其他相关信息...... Ergo,它必须返回到要检索的表的真实位置您请求的其他元数据,这对于简单排序记录的效率较低(假设您有这么小的数据集)。这样做的原因是,在(名称)列上对小数据集进行排序比根据索引检索值更快的CPU更快,然后对它们进行排序。

但是,由于我提到的确切原因,从任意大的表中检索大量宽记录时,通常不会使用索引。您可以给出计划器提示,这将强制它使用索引来验证我在这里提到的内容...您还可以通过一些大的因子来增加数据集,然后尝试选择它的一小部分来测试我的理论。