我现在已经阅读了其他几个关于此问题的堆栈溢出问题,但它仍然没有意义。
我正在试验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使用索引对结果进行排序?
答案 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更快,然后对它们进行排序。
但是,由于我提到的确切原因,从任意大的表中检索大量宽记录时,通常不会使用索引。您可以给出计划器提示,这将强制它使用索引来验证我在这里提到的内容...您还可以通过一些大的因子来增加数据集,然后尝试选择它的一小部分来测试我的理论。